Skip to content

Commit 0d700e9

Browse files
Refactor thread local storage
1 parent 7b9076f commit 0d700e9

File tree

3 files changed

+86
-93
lines changed

3 files changed

+86
-93
lines changed

src/gc.c

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,58 @@ HL_PRIM gc_pheader *hl_gc_get_page( void *v ) {
308308

309309
HL_API int hl_thread_id();
310310

311+
HL_PRIM int hl_atomic_add32(int *a, int b);
312+
313+
#ifdef HL_WIN
314+
static SRWLOCK free_list_mutex = SRWLOCK_INIT;
315+
static inline void lock_free_list() { AcquireSRWLockExclusive(&free_list_mutex); }
316+
static inline void unlock_free_list() { ReleaseSRWLockExclusive(&free_list_mutex); }
317+
#else
318+
#include <pthread.h>
319+
static pthread_mutex_t free_list_mutex = PTHREAD_MUTEX_INITIALIZER;
320+
static inline void lock_free_list() { pthread_mutex_lock(&free_list_mutex); }
321+
static inline void unlock_free_list() { pthread_mutex_unlock(&free_list_mutex); }
322+
#endif
323+
324+
static int tls_counter = 0;
325+
326+
struct tls_free_list {
327+
int key;
328+
struct tls_free_list *next;
329+
};
330+
331+
static struct tls_free_list * free_list;
332+
333+
int get_tls_slot() {
334+
lock_free_list();
335+
if (free_list) {
336+
struct tls_free_list *l = free_list;
337+
int key = l->key;
338+
free_list = l->next;
339+
free(l);
340+
unlock_free_list();
341+
return key;
342+
}
343+
unlock_free_list();
344+
return hl_atomic_add32(&tls_counter, 1);
345+
}
346+
347+
// this function should only run in the finalizer, which is called when all threads
348+
// are stopped
349+
void free_tls_slot(int key) {
350+
for (int i = 0; i < gc_threads.count; i++) {
351+
if (key < gc_threads.threads[i]->tls_arr_size) {
352+
gc_threads.threads[i]->tls_arr[key] = NULL;
353+
}
354+
}
355+
struct tls_free_list *l = malloc(sizeof(struct tls_free_list));
356+
l->key = key;
357+
lock_free_list();
358+
l->next = free_list;
359+
free_list = l;
360+
unlock_free_list();
361+
}
362+
311363
HL_API void hl_register_thread( void *stack_top ) {
312364
if( hl_get_thread() )
313365
hl_fatal("Thread already registered");
@@ -324,6 +376,9 @@ HL_API void hl_register_thread( void *stack_top ) {
324376
current_thread = t;
325377
hl_add_root(&t->exc_value);
326378
hl_add_root(&t->exc_handler);
379+
hl_add_root(&t->tls_arr);
380+
t->tls_arr_size = 0;
381+
t->tls_arr = NULL;
327382

328383
gc_global_lock(true);
329384
hl_thread_info **all = (hl_thread_info**)malloc(sizeof(void*) * (gc_threads.count + 1));
@@ -340,6 +395,7 @@ HL_API void hl_unregister_thread() {
340395
hl_fatal("Thread not registered");
341396
hl_remove_root(&t->exc_value);
342397
hl_remove_root(&t->exc_handler);
398+
hl_remove_root(&t->tls_arr);
343399
gc_global_lock(true);
344400
for(i=0;i<gc_threads.count;i++)
345401
if( gc_threads.threads[i] == t ) {

src/hl.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -785,7 +785,6 @@ HL_API void hl_condition_free(hl_condition *cond);
785785
HL_API hl_tls *hl_tls_alloc( bool gc_value );
786786
HL_API void hl_tls_set( hl_tls *l, void *value );
787787
HL_API void *hl_tls_get( hl_tls *l );
788-
HL_API void hl_tls_free( hl_tls *l );
789788

790789
// ----------------------- ALLOC --------------------------------------------------
791790

@@ -984,6 +983,8 @@ typedef struct {
984983
thread_t mach_thread_id;
985984
pthread_t pthread_id;
986985
#endif
986+
int tls_arr_size;
987+
void **tls_arr;
987988
} hl_thread_info;
988989

989990
typedef struct {

src/std/thread.c

Lines changed: 28 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,6 @@ struct _hl_condition {
6464
CRITICAL_SECTION cs;
6565
CONDITION_VARIABLE cond;
6666
};
67-
68-
struct _hl_tls {
69-
void (*free)( hl_tls * );
70-
DWORD tid;
71-
bool gc;
72-
};
73-
7467
#else
7568

7669
# include <pthread.h>
@@ -104,13 +97,6 @@ struct _hl_condition {
10497
pthread_mutex_t mutex;
10598
pthread_cond_t cond;
10699
};
107-
108-
struct _hl_tls {
109-
void (*free)( hl_tls * );
110-
pthread_key_t key;
111-
bool gc;
112-
};
113-
114100
#endif
115101

116102
// ----------------- ALLOC
@@ -463,95 +449,45 @@ DEFINE_PRIM(_VOID, condition_broadcast, _CONDITION)
463449

464450
// ----------------- THREAD LOCAL
465451

466-
#if defined(HL_THREADS)
467-
static void **_tls_get( hl_tls *t ) {
468-
# ifdef HL_WIN
469-
return (void**)TlsGetValue(t->tid);
470-
# else
471-
return (void**)pthread_getspecific(t->key);
472-
# endif
473-
}
474-
static void _tls_set( hl_tls *t, void *store ) {
475-
# ifdef HL_WIN
476-
TlsSetValue(t->tid, store);
477-
# else
478-
pthread_setspecific(t->key, store);
479-
# endif
480-
}
481-
#endif
452+
int get_tls_slot();
453+
void free_tls_slot(int id);
454+
455+
struct _hl_tls {
456+
void (*free)( hl_tls * );
457+
int key;
458+
bool gc;
459+
};
460+
461+
static void tls_free(hl_tls *l) { free_tls_slot(l->key); }
482462

483463
HL_PRIM hl_tls *hl_tls_alloc( bool gc_value ) {
484-
# if !defined(HL_THREADS)
485464
hl_tls *l = (hl_tls*)hl_gc_alloc_finalizer(sizeof(hl_tls));
486-
l->free = hl_tls_free;
487-
l->value = NULL;
488-
return l;
489-
# elif defined(HL_WIN)
490-
hl_tls *l = (hl_tls*)hl_gc_alloc_finalizer(sizeof(hl_tls));
491-
l->free = hl_tls_free;
492-
l->tid = TlsAlloc();
493-
l->gc = gc_value;
494-
TlsSetValue(l->tid,NULL);
495-
return l;
496-
# else
497-
hl_tls *l = (hl_tls*)hl_gc_alloc_finalizer(sizeof(hl_tls));
498-
l->free = hl_tls_free;
465+
l->free = tls_free;
499466
l->gc = gc_value;
500-
pthread_key_create(&l->key,NULL);
467+
l->key = get_tls_slot();
501468
return l;
502-
# endif
503-
}
504-
505-
HL_PRIM void hl_tls_free( hl_tls *l ) {
506-
# if !defined(HL_THREADS)
507-
free(l);
508-
# elif defined(HL_WIN)
509-
if( l->free ) {
510-
TlsFree(l->tid);
511-
l->free = NULL;
512-
}
513-
# else
514-
if( l->free ) {
515-
pthread_key_delete(l->key);
516-
l->free = NULL;
517-
}
518-
# endif
519469
}
520470

521471
HL_PRIM void hl_tls_set( hl_tls *l, void *v ) {
522-
# if !defined(HL_THREADS)
523-
l->value = v;
524-
# else
525-
if( l->gc ) {
526-
void **store = _tls_get(l);
527-
if( !store) {
528-
if( !v )
529-
return;
530-
store = (void**)malloc(sizeof(void*));
531-
hl_add_root(store);
532-
_tls_set(l, store);
533-
} else {
534-
if( !v ) {
535-
free(store);
536-
hl_remove_root(store);
537-
_tls_set(l, NULL);
538-
return;
539-
}
540-
}
541-
*store = v;
542-
} else
543-
_tls_set(l, v);
544-
# endif
472+
hl_thread_info *info = hl_get_thread();
473+
if (l->key >= info->tls_arr_size) {
474+
int new_max = info->tls_arr_size > 0 ? info->tls_arr_size * 2 : 16;
475+
new_max = l->key > new_max ? l->key : new_max;
476+
void **new_arr = hl_gc_alloc_raw(sizeof(void*) * new_max);
477+
memcpy(new_arr, info->tls_arr, info->tls_arr_size * sizeof(void*));
478+
info->tls_arr = new_arr;
479+
info->tls_arr_size = new_max;
480+
}
481+
info->tls_arr[l->key] = v;
545482
}
546483

547484
HL_PRIM void *hl_tls_get( hl_tls *l ) {
548-
# if !defined(HL_THREADS)
549-
return l->value;
550-
# else
551-
void **store = _tls_get(l);
552-
if( !l->gc ) return store;
553-
return store ? *store : NULL;
554-
# endif
485+
hl_thread_info *info = hl_get_thread();
486+
if (l->key < info->tls_arr_size) {
487+
return info->tls_arr[l->key];
488+
} else {
489+
return NULL;
490+
}
555491
}
556492

557493
#define _TLS _ABSTRACT(hl_tls)

0 commit comments

Comments
 (0)