diff options
author | Samuel Holland <samuel@sholland.org> | 2018-09-11 22:16:41 -0500 |
---|---|---|
committer | Samuel Holland <samuel@sholland.org> | 2018-09-11 22:31:22 -0500 |
commit | 67eb8c6c04a1b6c6fb85cf9cd6d7bdde489c4d5d (patch) | |
tree | 4ac964ad193b3f3c0a0ab577b0530aede4605d2f /libgcompat | |
parent | 938c8095e7456fbcdf4ce261bdb6dfa3a8e41b80 (diff) | |
download | gcompat-67eb8c6c04a1b6c6fb85cf9cd6d7bdde489c4d5d.tar.gz gcompat-67eb8c6c04a1b6c6fb85cf9cd6d7bdde489c4d5d.tar.bz2 gcompat-67eb8c6c04a1b6c6fb85cf9cd6d7bdde489c4d5d.tar.xz gcompat-67eb8c6c04a1b6c6fb85cf9cd6d7bdde489c4d5d.zip |
cxx_thread: Add __cxa_thread_atexit_impl
Signed-off-by: Samuel Holland <samuel@sholland.org>
Diffstat (limited to 'libgcompat')
-rw-r--r-- | libgcompat/cxx_thread.c | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/libgcompat/cxx_thread.c b/libgcompat/cxx_thread.c new file mode 100644 index 0000000..105e4c5 --- /dev/null +++ b/libgcompat/cxx_thread.c @@ -0,0 +1,56 @@ +#include <pthread.h> /* NULL, pthread_{key,once,{get,set}specific} */ +#include <stdlib.h> /* malloc, free */ + +#include "internal.h" + +struct dtor_node { + struct dtor_node *next; + void (*func)(void *); + void *obj; +}; + +static pthread_key_t key; +static pthread_once_t once = PTHREAD_ONCE_INIT; + +static void run_dtors(void *head) +{ + struct dtor_node *next, *node = head; + + while (node != NULL) { + next = node->next; + node->func(node->obj); + free(node); + node = next; + } +} + +static void create_key(void) +{ + int res = pthread_key_create(&key, run_dtors); + + GCOMPAT__assert_with_reason(res, "No key for thread_atexit list"); +} + +/** + * Register a destructor to run at thread exit. + * + * See + * https://sourceware.org/glibc/wiki/Destructor%20support%20for%20thread_local%20variables + */ +int __cxa_thread_atexit_impl(void (*func)(void *), void *obj, void *dso_symbol) +{ + struct dtor_node *node; + + pthread_once(&once, create_key); + + node = malloc(sizeof(*node)); + GCOMPAT__assert_with_reason(node, "No memory for thread_atexit node"); + node->next = pthread_getspecific(key); + node->func = func; + node->obj = obj; + + int res = pthread_setspecific(key, node); + GCOMPAT__assert_with_reason(!res, "Cannot update thread_atexit list"); + + return 0; +} |