libc/stdlib: Add __cxa_thread_atexit_impl() hook.
authorzrj <rimvydas.jasinskas@gmail.com>
Mon, 1 Apr 2019 17:16:47 +0000 (20:16 +0300)
committerzrj <zrj@dragonflybsd.org>
Sun, 7 Apr 2019 19:15:03 +0000 (22:15 +0300)
The __cxa_thread_atexit_impl() helper is needed for mainly c++ runtime
libraries to support destructors for thread local storage using LIFO.
The _thread_finalize() is implemented based on OpenBSD variant with few
exceptions: less restrictive destructors calling scheme and c++ runtime
preserves implementation details how it orders (or even uses) this libc
addition. Based on other BSDs and libsdc++/libc++ code this is least
intrusive method to have pthread_exit() hooks in libc runtime. By the
looks, in base system nothing was using libstdc++ internal version.

While there, enable __cxa_thread_atexit_impl() usage in gcc80 libstdc++.

gnu/lib/gcc80/libstdcxx/headers/config.h
lib/libc/gen/Symbol.map
lib/libc/include/libc_private.h
lib/libc/stdlib/Makefile.inc
lib/libc/stdlib/Symbol.map
lib/libc/stdlib/cxa_thread_atexit_impl.c [new file with mode: 0644]
lib/libc/stdlib/exit.c
lib/libc_r/uthread/uthread_exit.c
lib/libthread_xu/thread/thr_exit.c

index 48d4364..f902198 100644 (file)
 /* #undef HAVE___CXA_THREAD_ATEXIT */
 
 /* Define to 1 if you have the `__cxa_thread_atexit_impl' function. */
-/* #undef HAVE___CXA_THREAD_ATEXIT_IMPL */
+#define HAVE___CXA_THREAD_ATEXIT_IMPL 1
 
 /* Define as const if the declaration of iconv() needs const. */
 /* #undef ICONV_CONST */
index 0ff282e..554cf80 100644 (file)
@@ -689,6 +689,7 @@ DFprivate_1.0 {
     _rtld_thread_prefork;
     _rtld_thread_postfork;
     _rtld_thread_childfork;
+    _thread_finalize;
     _seekdir;
     _setcontext;
     _sigwait;
index 3ef5222..ecacb9a 100644 (file)
@@ -87,6 +87,11 @@ int _yp_check(char **);
  */
 extern const char *__progname;
 
+/*
+ * Notify libc that thread is exiting and its TLS destructors can be called.
+ */
+void _thread_finalize(void);
+
 /*
  * Function to clean up streams, called from abort() and exit().
  */
index a80357a..e765c2c 100644 (file)
@@ -8,7 +8,8 @@ CMAPS+= ${.CURDIR}/stdlib/Symbol.map
 
 MISRCS+=a64l.c abort.c abs.c atexit.c aligned_alloc.c \
        atof.c atoi.c atol.c atoll.c \
-       bsearch.c div.c exit.c getenv.c getopt.c getopt_long.c \
+       bsearch.c cxa_thread_atexit_impl.c \
+       div.c exit.c getenv.c getopt.c getopt_long.c \
        getsubopt.c hcreate.c heapsort.c imaxabs.c imaxdiv.c \
        insque.c l64a.c labs.c ldiv.c llabs.c lldiv.c lsearch.c \
        merge.c ptsname.c qsort.c qsort_r.c quick_exit.c \
index efb0c2e..4a800e3 100644 (file)
@@ -117,6 +117,7 @@ DF504.0 {
 };
 
 DF506.0 {
+    __cxa_thread_atexit_impl;
     reallocarray;
 };
 
diff --git a/lib/libc/stdlib/cxa_thread_atexit_impl.c b/lib/libc/stdlib/cxa_thread_atexit_impl.c
new file mode 100644 (file)
index 0000000..c0bcb68
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2019 The DragonFly Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/queue.h>
+#include "namespace.h"
+#include <link.h>
+#include <pthread.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+
+#define DTORS_ITERATIONS       5
+
+struct thread_dtorfn {
+       void (*func)(void *);
+       void *arg;
+       void *dso;
+       LIST_ENTRY(thread_dtorfn) entry;
+};
+static __thread LIST_HEAD(dtor_list, thread_dtorfn) dtors =
+    LIST_HEAD_INITIALIZER(dtors);
+
+int __cxa_thread_atexit_impl(void (*func)(void *), void *arg, void *dso);
+
+void
+_thread_finalize(void)
+{
+       struct dl_phdr_info phdr_info;
+       struct thread_dtorfn *fnp, *tdtor;
+       int i;
+
+       /*
+        * It is possible to get more destructors registered while
+        * unregistering them on thread exit.  Use maximum DTORS_ITERATIONS
+        * loops.  If dso is no longer available (dlclose()), skip it.
+        */
+       for (i = 0; i < DTORS_ITERATIONS && !LIST_EMPTY(&dtors); i++) {
+               LIST_FOREACH_MUTABLE(fnp, &dtors, entry, tdtor) {
+                       LIST_REMOVE(fnp, entry);
+                       if (_rtld_addr_phdr(fnp->dso, &phdr_info) &&
+                           __elf_phdr_match_addr(&phdr_info, fnp->func))
+                               fnp->func(fnp->arg);
+                       free(fnp);
+               }
+       }
+}
+
+int
+__cxa_thread_atexit_impl(void (*func)(void *), void *arg, void *dso)
+{
+       struct thread_dtorfn *fnp;
+
+       fnp = calloc(1, sizeof(*fnp));
+       if (fnp == NULL)
+               return -1;
+
+       fnp->func = func;
+       fnp->arg = arg;
+       fnp->dso = dso;
+       LIST_INSERT_HEAD(&dtors, fnp, entry);
+
+       return 0;
+}
index 89b5d4e..72f8c93 100644 (file)
@@ -28,7 +28,6 @@
  *
  * @(#)exit.c  8.1 (Berkeley) 6/4/93
  * $FreeBSD: src/lib/libc/stdlib/exit.c,v 1.9 2007/01/09 00:28:09 imp Exp $
- * $DragonFly: src/lib/libc/stdlib/exit.c,v 1.8 2005/11/20 12:37:48 swildner Exp $
  */
 
 #include "namespace.h"
@@ -61,6 +60,8 @@ exit(int status)
 
        _thread_autoinit_dummy_decl = 1;
 
+       /* Call TLS destructors, if any. */
+       _thread_finalize();
        __cxa_finalize(NULL);
        if (__cleanup)
                (*__cleanup)();
index 37ed7fc..0319b7c 100644 (file)
@@ -30,7 +30,6 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/lib/libc_r/uthread/uthread_exit.c,v 1.16.2.8 2002/10/22 14:44:03 fjoe Exp $
- * $DragonFly: src/lib/libc_r/uthread/uthread_exit.c,v 1.6 2007/01/08 21:41:53 dillon Exp $
  */
 #include <errno.h>
 #include <unistd.h>
@@ -39,6 +38,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <pthread.h>
+#include "libc_private.h"
 #include "pthread_private.h"
 
 #define FLAGS_IN_SCHEDQ        \
@@ -169,6 +169,9 @@ _pthread_exit(void *status)
                _thread_cleanupspecific();
        }
 
+       /* Call TLS destructors, if any */
+       _thread_finalize();
+
        /* Free thread-specific poll_data structure, if allocated: */
        if (curthread->poll_data.fds != NULL) {
                free(curthread->poll_data.fds);
index 37a2f27..baa76b7 100644 (file)
@@ -41,6 +41,7 @@
 #include <pthread.h>
 #include "un-namespace.h"
 
+#include "libc_private.h"
 #include "thr_private.h"
 
 static void    exit_thread(void) __dead2;
@@ -117,6 +118,8 @@ _pthread_exit(void *status)
        while (curthread->cleanup != NULL) {
                _pthread_cleanup_pop(1);
        }
+       /* Call TLS destructors, if any. */
+       _thread_finalize();
 
        exit_thread();
 }