@@ -74,34 +74,38 @@ static inline bool _msgpack_rmem_chunk_try_free(msgpack_rmem_chunk_t* c, void* m
7474 return false;
7575}
7676
77+ void _msgpack_rmem_chunk_free (msgpack_rmem_t * pm , msgpack_rmem_chunk_t * c );
78+
79+ /*
80+ * MSGPACK_RMEM_RACTOR_SAFE: the original implementation recycled fixed-size
81+ * pages from a process-global slab (msgpack_rmem_t s_rmem / s_stack_rmem),
82+ * mutating a shared bitmask with no locking. That made the C extension unsafe
83+ * to call from multiple Ractors (or threads) in parallel, and the page slab
84+ * could not declare rb_ext_ractor_safe(true).
85+ *
86+ * We instead hand out each page via Ruby's xmalloc/xfree. These are safe to
87+ * call from any Ractor's execution context, and freeing during GC sweep on a
88+ * different thread than the allocator (the common case for Unpacker_free's
89+ * RUBY_TYPED_FREE_IMMEDIATELY dfree callback) is correct. Pages are still
90+ * contiguous MSGPACK_RMEM_PAGE_SIZE blocks, so the buffer's intra-page
91+ * sub-allocation bookkeeping (rmem_owner / rmem_last / rmem_end) is unchanged.
92+ *
93+ * Trade-off: we lose the per-slab page-recycling fast path. The system
94+ * allocator (jemalloc in production Ruby) services these 4 KiB allocations from
95+ * per-thread arenas, so the overhead is small and, crucially, identical for
96+ * serial and pooled decode paths.
97+ */
7798static inline void * msgpack_rmem_alloc (msgpack_rmem_t * pm )
7899{
79- if (_msgpack_rmem_chunk_available (& pm -> head )) {
80- return _msgpack_rmem_chunk_alloc (& pm -> head );
81- }
82- return _msgpack_rmem_alloc2 (pm );
100+ (void )pm ;
101+ return xmalloc (MSGPACK_RMEM_PAGE_SIZE );
83102}
84103
85- void _msgpack_rmem_chunk_free (msgpack_rmem_t * pm , msgpack_rmem_chunk_t * c );
86-
87104static inline bool msgpack_rmem_free (msgpack_rmem_t * pm , void * mem )
88105{
89- if (_msgpack_rmem_chunk_try_free (& pm -> head , mem )) {
90- return true;
91- }
92-
93- /* search from last */
94- msgpack_rmem_chunk_t * c = pm -> array_last - 1 ;
95- msgpack_rmem_chunk_t * before_first = pm -> array_first - 1 ;
96- for (; c != before_first ; c -- ) {
97- if (_msgpack_rmem_chunk_try_free (c , mem )) {
98- if (c != pm -> array_first && c -> mask == 0xffffffff ) {
99- _msgpack_rmem_chunk_free (pm , c );
100- }
101- return true;
102- }
103- }
104- return false;
106+ (void )pm ;
107+ xfree (mem );
108+ return true;
105109}
106110
107111
0 commit comments