@@ -41,6 +41,8 @@ typedef struct {
4141 ts_allocate_ctor ctor ;
4242 ts_allocate_dtor dtor ;
4343 ptrdiff_t fast_offset ;
44+ /* When set, storage comes from __thread memory instead of being allocated by TSRM. */
45+ void * (* tls_addr )(void );
4446 int done ;
4547} tsrm_resource_type ;
4648
@@ -164,14 +166,20 @@ TSRM_API bool tsrm_startup(int expected_threads, int expected_resources, int deb
164166
165167static void ts_free_resources (tsrm_tls_entry * thread_resources )
166168{
169+ bool own_thread = thread_resources -> thread_id == tsrm_thread_id ();
170+
167171 /* Need to destroy in reverse order to respect dependencies. */
168172 for (int i = thread_resources -> count - 1 ; i >= 0 ; i -- ) {
169173 if (!resource_types_table [i ].done ) {
174+ /* A __thread block of a foreign thread is inaccessible. */
175+ if (resource_types_table [i ].tls_addr && !own_thread ) {
176+ continue ;
177+ }
170178 if (resource_types_table [i ].dtor ) {
171179 resource_types_table [i ].dtor (thread_resources -> storage [i ]);
172180 }
173181
174- if (!resource_types_table [i ].fast_offset ) {
182+ if (!resource_types_table [i ].fast_offset && ! resource_types_table [ i ]. tls_addr ) {
175183 free (thread_resources -> storage [i ]);
176184 }
177185 }
@@ -258,7 +266,10 @@ static void tsrm_update_active_threads(void)
258266
259267 p -> storage = (void * ) realloc (p -> storage , sizeof (void * )* id_count );
260268 for (j = p -> count ; j < id_count ; j ++ ) {
261- if (resource_types_table [j ].fast_offset ) {
269+ if (resource_types_table [j ].tls_addr ) {
270+ TSRM_ASSERT (p -> thread_id == tsrm_thread_id ());
271+ p -> storage [j ] = resource_types_table [j ].tls_addr ();
272+ } else if (resource_types_table [j ].fast_offset ) {
262273 p -> storage [j ] = (void * ) (((char * )p ) + resource_types_table [j ].fast_offset );
263274 } else {
264275 p -> storage [j ] = (void * ) malloc (resource_types_table [j ].size );
@@ -303,6 +314,7 @@ TSRM_API ts_rsrc_id ts_allocate_id(ts_rsrc_id *rsrc_id, size_t size, ts_allocate
303314 resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].ctor = ctor ;
304315 resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].dtor = dtor ;
305316 resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].fast_offset = 0 ;
317+ resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].tls_addr = NULL ;
306318 resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].done = 0 ;
307319
308320 tsrm_update_active_threads ();
@@ -381,6 +393,7 @@ TSRM_API ts_rsrc_id ts_allocate_fast_id_at(ts_rsrc_id *rsrc_id, size_t *offset,
381393 resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].ctor = ctor ;
382394 resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].dtor = dtor ;
383395 resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].fast_offset = * offset ;
396+ resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].tls_addr = NULL ;
384397 resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].done = 0 ;
385398
386399 tsrm_update_active_threads ();
@@ -390,6 +403,41 @@ TSRM_API ts_rsrc_id ts_allocate_fast_id_at(ts_rsrc_id *rsrc_id, size_t *offset,
390403 return * rsrc_id ;
391404}
392405
406+ /* allocates a resource id whose per-thread storage is a native __thread block */
407+ TSRM_API ts_rsrc_id ts_allocate_tls_id (ts_rsrc_id * rsrc_id , void * (* tls_addr )(void ), size_t size , ts_allocate_ctor ctor , ts_allocate_dtor dtor )
408+ {
409+ TSRM_ERROR ((TSRM_ERROR_LEVEL_CORE , "Obtaining a new TLS resource id, %d bytes" , size ));
410+
411+ tsrm_mutex_lock (tsmm_mutex );
412+
413+ * rsrc_id = TSRM_SHUFFLE_RSRC_ID (id_count ++ );
414+
415+ if (resource_types_table_size < id_count ) {
416+ tsrm_resource_type * _tmp ;
417+ _tmp = (tsrm_resource_type * ) realloc (resource_types_table , sizeof (tsrm_resource_type )* id_count );
418+ if (!_tmp ) {
419+ TSRM_ERROR ((TSRM_ERROR_LEVEL_ERROR , "Unable to allocate storage for resource" ));
420+ * rsrc_id = 0 ;
421+ tsrm_mutex_unlock (tsmm_mutex );
422+ return 0 ;
423+ }
424+ resource_types_table = _tmp ;
425+ resource_types_table_size = id_count ;
426+ }
427+ resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].size = size ;
428+ resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].ctor = ctor ;
429+ resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].dtor = dtor ;
430+ resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].fast_offset = 0 ;
431+ resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].tls_addr = tls_addr ;
432+ resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].done = 0 ;
433+
434+ tsrm_update_active_threads ();
435+ tsrm_mutex_unlock (tsmm_mutex );
436+
437+ TSRM_ERROR ((TSRM_ERROR_LEVEL_CORE , "Successfully allocated new TLS resource id %d" , * rsrc_id ));
438+ return * rsrc_id ;
439+ }
440+
393441static void set_thread_local_storage_resource_to (tsrm_tls_entry * thread_resource )
394442{
395443 tsrm_tls_set (thread_resource );
@@ -422,7 +470,9 @@ static void allocate_new_resource(tsrm_tls_entry **thread_resources_ptr, THREAD_
422470 if (resource_types_table [i ].done ) {
423471 (* thread_resources_ptr )-> storage [i ] = NULL ;
424472 } else {
425- if (resource_types_table [i ].fast_offset ) {
473+ if (resource_types_table [i ].tls_addr ) {
474+ (* thread_resources_ptr )-> storage [i ] = resource_types_table [i ].tls_addr ();
475+ } else if (resource_types_table [i ].fast_offset ) {
426476 (* thread_resources_ptr )-> storage [i ] = (void * ) (((char * )(* thread_resources_ptr )) + resource_types_table [i ].fast_offset );
427477 } else {
428478 (* thread_resources_ptr )-> storage [i ] = (void * ) malloc (resource_types_table [i ].size );
@@ -510,7 +560,9 @@ TSRM_API void *ts_resource_ex(ts_rsrc_id id, THREAD_T *th_id)
510560 /* In case that extensions don't use the pointer passed from the dtor, but incorrectly
511561 * use the global pointer, we need to setup the global pointer temporarily here. */
512562 set_thread_local_storage_resource_to (thread_resources );
513- /* Free up the old resource from the old thread instance */
563+ /* Dead thread with a recycled id: its __thread blocks are gone, and this
564+ * thread's blocks were never constructed, so keep tls dtors from running. */
565+ thread_resources -> thread_id = 0 ;
514566 ts_free_resources (thread_resources );
515567 free ((char * ) thread_resources - tsrm_reserved_front );
516568 /* Allocate a new resource at the same point in the linked list, and relink the next pointer */
@@ -584,7 +636,7 @@ void ts_free_id(ts_rsrc_id id)
584636 if (resource_types_table [rsrc_id ].dtor ) {
585637 resource_types_table [rsrc_id ].dtor (p -> storage [rsrc_id ]);
586638 }
587- if (!resource_types_table [rsrc_id ].fast_offset ) {
639+ if (!resource_types_table [rsrc_id ].fast_offset && ! resource_types_table [ rsrc_id ]. tls_addr ) {
588640 free (p -> storage [rsrc_id ]);
589641 }
590642 }
0 commit comments