@@ -42,6 +42,8 @@ typedef struct {
4242 ts_allocate_ctor ctor ;
4343 ts_allocate_dtor dtor ;
4444 size_t fast_offset ;
45+ /* When set, storage comes from __thread memory instead of being allocated by TSRM. */
46+ void * (* tls_addr )(void );
4547 int done ;
4648} tsrm_resource_type ;
4749
@@ -163,14 +165,19 @@ TSRM_API bool tsrm_startup(int expected_threads, int expected_resources, int deb
163165
164166static void ts_free_resources (tsrm_tls_entry * thread_resources )
165167{
168+ bool own_thread = thread_resources -> thread_id == tsrm_thread_id ();
169+
166170 /* Need to destroy in reverse order to respect dependencies. */
167171 for (int i = thread_resources -> count - 1 ; i >= 0 ; i -- ) {
168172 if (!resource_types_table [i ].done ) {
173+ if (resource_types_table [i ].tls_addr && !own_thread ) {
174+ continue ;
175+ }
169176 if (resource_types_table [i ].dtor ) {
170177 resource_types_table [i ].dtor (thread_resources -> storage [i ]);
171178 }
172179
173- if (!resource_types_table [i ].fast_offset ) {
180+ if (!resource_types_table [i ].fast_offset && ! resource_types_table [ i ]. tls_addr ) {
174181 free (thread_resources -> storage [i ]);
175182 }
176183 }
@@ -256,7 +263,10 @@ static void tsrm_update_active_threads(void)
256263
257264 p -> storage = (void * ) realloc (p -> storage , sizeof (void * )* id_count );
258265 for (j = p -> count ; j < id_count ; j ++ ) {
259- if (resource_types_table [j ].fast_offset ) {
266+ if (resource_types_table [j ].tls_addr ) {
267+ TSRM_ASSERT (p -> thread_id == tsrm_thread_id ());
268+ p -> storage [j ] = resource_types_table [j ].tls_addr ();
269+ } else if (resource_types_table [j ].fast_offset ) {
260270 p -> storage [j ] = (void * ) (((char * )p ) + resource_types_table [j ].fast_offset );
261271 } else {
262272 p -> storage [j ] = (void * ) malloc (resource_types_table [j ].size );
@@ -301,6 +311,7 @@ TSRM_API ts_rsrc_id ts_allocate_id(ts_rsrc_id *rsrc_id, size_t size, ts_allocate
301311 resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].ctor = ctor ;
302312 resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].dtor = dtor ;
303313 resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].fast_offset = 0 ;
314+ resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].tls_addr = NULL ;
304315 resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].done = 0 ;
305316
306317 tsrm_update_active_threads ();
@@ -359,6 +370,7 @@ TSRM_API ts_rsrc_id ts_allocate_fast_id(ts_rsrc_id *rsrc_id, size_t *offset, siz
359370 resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].ctor = ctor ;
360371 resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].dtor = dtor ;
361372 resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].fast_offset = * offset ;
373+ resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].tls_addr = NULL ;
362374 resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].done = 0 ;
363375
364376 tsrm_update_active_threads ();
@@ -368,6 +380,41 @@ TSRM_API ts_rsrc_id ts_allocate_fast_id(ts_rsrc_id *rsrc_id, size_t *offset, siz
368380 return * rsrc_id ;
369381}/*}}}*/
370382
383+ /* allocates a resource id whose per-thread storage is a native __thread block */
384+ 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 )
385+ {/*{{{*/
386+ TSRM_ERROR ((TSRM_ERROR_LEVEL_CORE , "Obtaining a new TLS resource id, %d bytes" , size ));
387+
388+ tsrm_mutex_lock (tsmm_mutex );
389+
390+ * rsrc_id = TSRM_SHUFFLE_RSRC_ID (id_count ++ );
391+
392+ if (resource_types_table_size < id_count ) {
393+ tsrm_resource_type * _tmp ;
394+ _tmp = (tsrm_resource_type * ) realloc (resource_types_table , sizeof (tsrm_resource_type )* id_count );
395+ if (!_tmp ) {
396+ TSRM_ERROR ((TSRM_ERROR_LEVEL_ERROR , "Unable to allocate storage for resource" ));
397+ * rsrc_id = 0 ;
398+ tsrm_mutex_unlock (tsmm_mutex );
399+ return 0 ;
400+ }
401+ resource_types_table = _tmp ;
402+ resource_types_table_size = id_count ;
403+ }
404+ resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].size = size ;
405+ resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].ctor = ctor ;
406+ resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].dtor = dtor ;
407+ resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].fast_offset = 0 ;
408+ resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].tls_addr = tls_addr ;
409+ resource_types_table [TSRM_UNSHUFFLE_RSRC_ID (* rsrc_id )].done = 0 ;
410+
411+ tsrm_update_active_threads ();
412+ tsrm_mutex_unlock (tsmm_mutex );
413+
414+ TSRM_ERROR ((TSRM_ERROR_LEVEL_CORE , "Successfully allocated new TLS resource id %d" , * rsrc_id ));
415+ return * rsrc_id ;
416+ }/*}}}*/
417+
371418static void set_thread_local_storage_resource_to (tsrm_tls_entry * thread_resource )
372419{
373420 tsrm_tls_set (thread_resource );
@@ -397,7 +444,9 @@ static void allocate_new_resource(tsrm_tls_entry **thread_resources_ptr, THREAD_
397444 if (resource_types_table [i ].done ) {
398445 (* thread_resources_ptr )-> storage [i ] = NULL ;
399446 } else {
400- if (resource_types_table [i ].fast_offset ) {
447+ if (resource_types_table [i ].tls_addr ) {
448+ (* thread_resources_ptr )-> storage [i ] = resource_types_table [i ].tls_addr ();
449+ } else if (resource_types_table [i ].fast_offset ) {
401450 (* thread_resources_ptr )-> storage [i ] = (void * ) (((char * )(* thread_resources_ptr )) + resource_types_table [i ].fast_offset );
402451 } else {
403452 (* thread_resources_ptr )-> storage [i ] = (void * ) malloc (resource_types_table [i ].size );
@@ -485,7 +534,8 @@ TSRM_API void *ts_resource_ex(ts_rsrc_id id, THREAD_T *th_id)
485534 /* In case that extensions don't use the pointer passed from the dtor, but incorrectly
486535 * use the global pointer, we need to setup the global pointer temporarily here. */
487536 set_thread_local_storage_resource_to (thread_resources );
488- /* Free up the old resource from the old thread instance */
537+ /* Dead thread, recycled id: already freed, so just zero it. */
538+ thread_resources -> thread_id = 0 ;
489539 ts_free_resources (thread_resources );
490540 free (thread_resources );
491541 /* Allocate a new resource at the same point in the linked list, and relink the next pointer */
@@ -559,7 +609,7 @@ void ts_free_id(ts_rsrc_id id)
559609 if (resource_types_table [rsrc_id ].dtor ) {
560610 resource_types_table [rsrc_id ].dtor (p -> storage [rsrc_id ]);
561611 }
562- if (!resource_types_table [rsrc_id ].fast_offset ) {
612+ if (!resource_types_table [rsrc_id ].fast_offset && ! resource_types_table [ rsrc_id ]. tls_addr ) {
563613 free (p -> storage [rsrc_id ]);
564614 }
565615 }
0 commit comments