summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.rst5
-rw-r--r--Makefile1
-rw-r--r--libgcompat/cxx_thread.c56
3 files changed, 62 insertions, 0 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index ee9851d..2902cb3 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -17,6 +17,11 @@ Build system
* Allow building against libucontext.
+cxx_thread
+----------
+
+* Add __cxa_thread_atexit_impl.
+
math
----
diff --git a/Makefile b/Makefile
index 06af84f..74c25f6 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,7 @@
LIBGCOMPAT_INCLUDE = \
libgcompat/alias.h
LIBGCOMPAT_SRC = \
+ libgcompat/cxx_thread.c \
libgcompat/dlfcn.c \
libgcompat/error.c \
libgcompat/execinfo.c \
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;
+}