@@ -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 }
@@ -180,7 +188,9 @@ static void ts_free_resources(tsrm_tls_entry *thread_resources)
180188 free (thread_resources -> storage );
181189}
182190
183- /* Shutdown TSRM (call once for the entire process) */
191+ /* Shutdown TSRM (call once for the entire process). Tears down every thread left
192+ * in the table. For resources allocated with ts_allocate_tls_id(), only the dtor
193+ * of the calling thread is invoked. */
184194TSRM_API void tsrm_shutdown (void )
185195{/*{{{*/
186196 if (is_thread_shutdown ) {
@@ -258,7 +268,10 @@ static void tsrm_update_active_threads(void)
258268
259269 p -> storage = (void * ) realloc (p -> storage , sizeof (void * )* id_count );
260270 for (j = p -> count ; j < id_count ; j ++ ) {
261- if (resource_types_table [j ].fast_offset ) {
271+ if (resource_types_table [j ].tls_addr ) {
272+ TSRM_ASSERT (p -> thread_id == tsrm_thread_id ());
273+ p -> storage [j ] = resource_types_table [j ].tls_addr ();
274+ } else if (resource_types_table [j ].fast_offset ) {
262275 p -> storage [j ] = (void * ) (((char * )p ) + resource_types_table [j ].fast_offset );
263276 } else {
264277 p -> storage [j ] = (void * ) malloc (resource_types_table [j ].size );
@@ -303,6 +316,7 @@ TSRM_API ts_rsrc_id ts_allocate_id(ts_rsrc_id *rsrc_id, size_t size, ts_allocate
303316 resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].ctor = ctor ;
304317 resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].dtor = dtor ;
305318 resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].fast_offset = 0 ;
319+ resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].tls_addr = NULL ;
306320 resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].done = 0 ;
307321
308322 tsrm_update_active_threads ();
@@ -381,6 +395,7 @@ TSRM_API ts_rsrc_id ts_allocate_fast_id_at(ts_rsrc_id *rsrc_id, size_t *offset,
381395 resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].ctor = ctor ;
382396 resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].dtor = dtor ;
383397 resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].fast_offset = * offset ;
398+ resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].tls_addr = NULL ;
384399 resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].done = 0 ;
385400
386401 tsrm_update_active_threads ();
@@ -390,6 +405,41 @@ TSRM_API ts_rsrc_id ts_allocate_fast_id_at(ts_rsrc_id *rsrc_id, size_t *offset,
390405 return * rsrc_id ;
391406}
392407
408+ /* allocates a resource id whose per-thread storage is a native __thread block */
409+ 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 )
410+ {
411+ TSRM_ERROR ((TSRM_ERROR_LEVEL_CORE , "Obtaining a new TLS resource id, %d bytes" , size ));
412+
413+ tsrm_mutex_lock (tsmm_mutex );
414+
415+ * rsrc_id = TSRM_SHUFFLE_RSRC_ID (id_count ++ );
416+
417+ if (resource_types_table_size < id_count ) {
418+ tsrm_resource_type * _tmp ;
419+ _tmp = (tsrm_resource_type * ) realloc (resource_types_table , sizeof (tsrm_resource_type )* id_count );
420+ if (!_tmp ) {
421+ TSRM_ERROR ((TSRM_ERROR_LEVEL_ERROR , "Unable to allocate storage for resource" ));
422+ * rsrc_id = 0 ;
423+ tsrm_mutex_unlock (tsmm_mutex );
424+ return 0 ;
425+ }
426+ resource_types_table = _tmp ;
427+ resource_types_table_size = id_count ;
428+ }
429+ resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].size = size ;
430+ resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].ctor = ctor ;
431+ resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].dtor = dtor ;
432+ resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].fast_offset = 0 ;
433+ resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].tls_addr = tls_addr ;
434+ resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].done = 0 ;
435+
436+ tsrm_update_active_threads ();
437+ tsrm_mutex_unlock (tsmm_mutex );
438+
439+ TSRM_ERROR ((TSRM_ERROR_LEVEL_CORE , "Successfully allocated new TLS resource id %d" , * rsrc_id ));
440+ return * rsrc_id ;
441+ }
442+
393443static void set_thread_local_storage_resource_to (tsrm_tls_entry * thread_resource )
394444{
395445 tsrm_tls_set (thread_resource );
@@ -422,7 +472,9 @@ static void allocate_new_resource(tsrm_tls_entry **thread_resources_ptr, THREAD_
422472 if (resource_types_table [i ].done ) {
423473 (* thread_resources_ptr )-> storage [i ] = NULL ;
424474 } else {
425- if (resource_types_table [i ].fast_offset ) {
475+ if (resource_types_table [i ].tls_addr ) {
476+ (* thread_resources_ptr )-> storage [i ] = resource_types_table [i ].tls_addr ();
477+ } else if (resource_types_table [i ].fast_offset ) {
426478 (* thread_resources_ptr )-> storage [i ] = (void * ) (((char * )(* thread_resources_ptr )) + resource_types_table [i ].fast_offset );
427479 } else {
428480 (* thread_resources_ptr )-> storage [i ] = (void * ) malloc (resource_types_table [i ].size );
@@ -510,7 +562,9 @@ TSRM_API void *ts_resource_ex(ts_rsrc_id id, THREAD_T *th_id)
510562 /* In case that extensions don't use the pointer passed from the dtor, but incorrectly
511563 * use the global pointer, we need to setup the global pointer temporarily here. */
512564 set_thread_local_storage_resource_to (thread_resources );
513- /* Free up the old resource from the old thread instance */
565+ /* Dead thread with a recycled id: its __thread blocks are gone, and this
566+ * thread's blocks were never constructed, so keep tls dtors from running. */
567+ thread_resources -> thread_id = 0 ;
514568 ts_free_resources (thread_resources );
515569 free ((char * ) thread_resources - tsrm_reserved_front );
516570 /* Allocate a new resource at the same point in the linked list, and relink the next pointer */
@@ -584,7 +638,7 @@ void ts_free_id(ts_rsrc_id id)
584638 if (resource_types_table [rsrc_id ].dtor ) {
585639 resource_types_table [rsrc_id ].dtor (p -> storage [rsrc_id ]);
586640 }
587- if (!resource_types_table [rsrc_id ].fast_offset ) {
641+ if (!resource_types_table [rsrc_id ].fast_offset && ! resource_types_table [ rsrc_id ]. tls_addr ) {
588642 free (p -> storage [rsrc_id ]);
589643 }
590644 }
0 commit comments