This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH v4] Destructor support for C++11 thread_local variables


Hi,

Here's another iteration of the patch rebased on top of Roland's
clock_* changes.  I have also added a test case to verify the DSO
unload behaviour using a C program instead of trying to figure out the
gcc version.  Thanks to Jakub for the idea of figuring out the code
generated by gcc and writing the test case based on it using __thread
that does not depend on the compiler.

Regards,
Siddhesh


ChangeLog:
2012-10-30  Siddhesh Poyarekar  <siddhesh@redhat.com>

	* include/link.h (struct link_map): New member l_tls_dtor_count.
	* include/stdlib.h (__cxa_thread_atexit_impl): Declare.
	(__call_tls_dtors): Likewise.
	* sysdeps/unix/sysv/linux/i386/nptl/libc.abilist: Add
	__cxa_thread_atexit_impl.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/nptl/libc.abilist:
	Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/nptl/libc.abilist:
	Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-32/nptl/libc.abilist:
	Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-64/nptl/libc.abilist:
	Likewise.
	* sysdeps/unix/sysv/linux/sh/nptl/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc32/nptl/libc.abilist:
	Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc64/nptl/libc.abilist:
	Likewise.
	* sysdeps/unix/sysv/linux/x86_64/64/nptl/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/x86_64/x32/nptl/libc.abilist:
	Likewise.
	* stdlib/Makefile (routines): Add __cxa_thread_atexit_impl.
	(tests): Add test case tst-tls-atexit.
	(modules-names): Add shared library for tst-tls-atexit.
	* stdlib/Versions (GLIBC_2.17): Add __cxa_thread_atexit_impl.
	(GLIBC_PRIVATE): Add __call_tls_dtors.
	* stdlib/cxa_thread_atexit_impl.c: New file with helper function
	for libstdc++.
	* stdlib/exit.c (__run_exit_handlers): Call __call_tls_dtors.
	* stdlib/tst-tls-atexit.c: New test case.
	* stdlib/tst-tls-atexit-lib.c: New test case.


ChangeLog.alpha:
2012-10-30  Siddhesh Poyarekar  <siddhesh@redhat.com>

	* sysdeps/unix/sysv/linux/alpha/nptl/libc.abilist: Add
	__cxa_thread_atexit_impl.


ChangeLog.arm:
2012-10-30  Siddhesh Poyarekar  <siddhesh@redhat.com>

	* sysdeps/unix/sysv/linux/arm/nptl/libc.abilist: Add
	__cxa_thread_atexit_impl.


ChangeLog.ia64:
2012-10-30  Siddhesh Poyarekar  <siddhesh@redhat.com>

	* sysdeps/unix/sysv/linux/ia64/nptl/libc.abilist: Add
	__cxa_thread_atexit_impl.


ChangeLog.m68k:
2012-10-30  Siddhesh Poyarekar  <siddhesh@redhat.com>

	* sysdeps/unix/sysv/linux/m68k/coldfire/nptl/libc.abilist: Add
	__cxa_thread_atexit_impl.
	* sysdeps/unix/sysv/linux/m68k/m680x0/nptl/libc.abilist:
	Likewise.


ChangeLog.mips:
2012-10-30  Siddhesh Poyarekar  <siddhesh@redhat.com>

	* sysdeps/unix/sysv/linux/mips/mips32/nptl/libc.abilist: Add
	__cxa_thread_atexit_impl.
	* sysdeps/unix/sysv/linux/mips/mips64/n32/nptl/libc.abilist:
	Likewise.
	* sysdeps/unix/sysv/linux/mips/mips64/n64/nptl/libc.abilist:
	Likewise.


ChangeLog.powerpc:
2012-10-30  Siddhesh Poyarekar  <siddhesh@redhat.com>

	* sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/nptl/libc.abilist:
	Add __cxa_thread_atexit_impl.
	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/nptl/libc.abilist:
	Likewise.


ChangeLog.tile:
2012-10-30  Siddhesh Poyarekar  <siddhesh@redhat.com>

	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/nptl/libc.abilist:
	Add __cxa_thread_atexit_impl.
	* sysdeps/unix/sysv/linux/tile/tilepro/nptl/libc.abilist:
	Likewise.

diff --git a/include/link.h b/include/link.h
index f0c8ad5..2e7147f 100644
--- a/include/link.h
+++ b/include/link.h
@@ -301,6 +301,9 @@ struct link_map
     /* Index of the module in the dtv array.  */
     size_t l_tls_modid;
 
+    /* Number of thread_local objects constructed by this DSO.  */
+    size_t l_tls_dtor_count;
+
     /* Information used to change permission after the relocations are
        done.  */
     ElfW(Addr) l_relro_addr;
diff --git a/include/stdlib.h b/include/stdlib.h
index d45b2f0..4387394 100644
--- a/include/stdlib.h
+++ b/include/stdlib.h
@@ -99,6 +99,10 @@ extern int __cxa_atexit (void (*func) (void *), void *arg, void *d);
 extern int __cxa_atexit_internal (void (*func) (void *), void *arg, void *d)
      attribute_hidden;
 
+extern int __cxa_thread_atexit_impl (void (*func) (void *), void *arg,
+				     void *d);
+extern void __call_tls_dtors (void);
+
 extern void __cxa_finalize (void *d);
 
 extern int __posix_memalign (void **memptr, size_t alignment, size_t size);
diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c
index 197dfa7..34c0d30 100644
--- a/nptl/pthread_create.c
+++ b/nptl/pthread_create.c
@@ -311,6 +311,9 @@ start_thread (void *arg)
 #endif
     }
 
+  /* Call destructors for the thread_local TLS variables.  */
+  __call_tls_dtors ();
+
   /* Run the destructor for the thread-local data.  */
   __nptl_deallocate_tsd ();
 
diff --git a/ports/sysdeps/unix/sysv/linux/alpha/nptl/libc.abilist b/ports/sysdeps/unix/sysv/linux/alpha/nptl/libc.abilist
index 1d0cc7e..30ca78e 100644
--- a/ports/sysdeps/unix/sysv/linux/alpha/nptl/libc.abilist
+++ b/ports/sysdeps/unix/sysv/linux/alpha/nptl/libc.abilist
@@ -1818,6 +1818,7 @@ GLIBC_2.17
  clock_gettime F
  clock_nanosleep F
  clock_settime F
+ __cxa_thread_atexit_impl F
  secure_getenv F
 GLIBC_2.2
  GLIBC_2.2 A
diff --git a/ports/sysdeps/unix/sysv/linux/arm/nptl/libc.abilist b/ports/sysdeps/unix/sysv/linux/arm/nptl/libc.abilist
index ceab6b2..256d095 100644
--- a/ports/sysdeps/unix/sysv/linux/arm/nptl/libc.abilist
+++ b/ports/sysdeps/unix/sysv/linux/arm/nptl/libc.abilist
@@ -85,6 +85,7 @@ GLIBC_2.17
  clock_gettime F
  clock_nanosleep F
  clock_settime F
+ __cxa_thread_atexit_impl F
  secure_getenv F
 GLIBC_2.4
  GLIBC_2.4 A
diff --git a/ports/sysdeps/unix/sysv/linux/ia64/nptl/libc.abilist b/ports/sysdeps/unix/sysv/linux/ia64/nptl/libc.abilist
index b3510fe..f9b3388 100644
--- a/ports/sysdeps/unix/sysv/linux/ia64/nptl/libc.abilist
+++ b/ports/sysdeps/unix/sysv/linux/ia64/nptl/libc.abilist
@@ -85,6 +85,7 @@ GLIBC_2.17
  clock_gettime F
  clock_nanosleep F
  clock_settime F
+ __cxa_thread_atexit_impl F
  secure_getenv F
 GLIBC_2.2
  GLIBC_2.2 A
diff --git a/ports/sysdeps/unix/sysv/linux/m68k/coldfire/nptl/libc.abilist b/ports/sysdeps/unix/sysv/linux/m68k/coldfire/nptl/libc.abilist
index 3c40379..6ecf963 100644
--- a/ports/sysdeps/unix/sysv/linux/m68k/coldfire/nptl/libc.abilist
+++ b/ports/sysdeps/unix/sysv/linux/m68k/coldfire/nptl/libc.abilist
@@ -86,6 +86,7 @@ GLIBC_2.17
  clock_gettime F
  clock_nanosleep F
  clock_settime F
+ __cxa_thread_atexit_impl F
  secure_getenv F
 GLIBC_2.4
  GLIBC_2.4 A
diff --git a/ports/sysdeps/unix/sysv/linux/m68k/m680x0/nptl/libc.abilist b/ports/sysdeps/unix/sysv/linux/m68k/m680x0/nptl/libc.abilist
index f998b1b..73cf4d3 100644
--- a/ports/sysdeps/unix/sysv/linux/m68k/m680x0/nptl/libc.abilist
+++ b/ports/sysdeps/unix/sysv/linux/m68k/m680x0/nptl/libc.abilist
@@ -1774,6 +1774,7 @@ GLIBC_2.17
  clock_gettime F
  clock_nanosleep F
  clock_settime F
+ __cxa_thread_atexit_impl F
  secure_getenv F
 GLIBC_2.2
  GLIBC_2.2 A
diff --git a/ports/sysdeps/unix/sysv/linux/mips/mips32/nptl/libc.abilist b/ports/sysdeps/unix/sysv/linux/mips/mips32/nptl/libc.abilist
index 7378869..bcaa0bc 100644
--- a/ports/sysdeps/unix/sysv/linux/mips/mips32/nptl/libc.abilist
+++ b/ports/sysdeps/unix/sysv/linux/mips/mips32/nptl/libc.abilist
@@ -2249,4 +2249,5 @@ GLIBC_2.17
  clock_gettime F
  clock_nanosleep F
  clock_settime F
+ __cxa_thread_atexit_impl F
  secure_getenv F
diff --git a/ports/sysdeps/unix/sysv/linux/mips/mips64/n32/nptl/libc.abilist b/ports/sysdeps/unix/sysv/linux/mips/mips64/n32/nptl/libc.abilist
index 2a0e2a2..5cd77ab 100644
--- a/ports/sysdeps/unix/sysv/linux/mips/mips64/n32/nptl/libc.abilist
+++ b/ports/sysdeps/unix/sysv/linux/mips/mips64/n32/nptl/libc.abilist
@@ -1392,6 +1392,7 @@ GLIBC_2.16
  timespec_get F
 GLIBC_2.17
  GLIBC_2.17 A
+ __cxa_thread_atexit_impl F
  secure_getenv F
 GLIBC_2.2
  GLIBC_2.2 A
diff --git a/ports/sysdeps/unix/sysv/linux/mips/mips64/n64/nptl/libc.abilist b/ports/sysdeps/unix/sysv/linux/mips/mips64/n64/nptl/libc.abilist
index 22b3068..14bba32 100644
--- a/ports/sysdeps/unix/sysv/linux/mips/mips64/n64/nptl/libc.abilist
+++ b/ports/sysdeps/unix/sysv/linux/mips/mips64/n64/nptl/libc.abilist
@@ -1395,6 +1395,7 @@ GLIBC_2.17
  clock_gettime F
  clock_nanosleep F
  clock_settime F
+ __cxa_thread_atexit_impl F
  secure_getenv F
 GLIBC_2.2
  GLIBC_2.2 A
diff --git a/ports/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/nptl/libc.abilist b/ports/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/nptl/libc.abilist
index f2682b3..b9d2193 100644
--- a/ports/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/nptl/libc.abilist
+++ b/ports/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/nptl/libc.abilist
@@ -1779,6 +1779,7 @@ GLIBC_2.17
  clock_gettime F
  clock_nanosleep F
  clock_settime F
+ __cxa_thread_atexit_impl F
  secure_getenv F
  __ppc_get_timebase_freq F
 GLIBC_2.2
diff --git a/ports/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/nptl/libc.abilist b/ports/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/nptl/libc.abilist
index d79b2df..41677b2 100644
--- a/ports/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/nptl/libc.abilist
+++ b/ports/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/nptl/libc.abilist
@@ -2087,4 +2087,5 @@ GLIBC_2.17
  clock_gettime F
  clock_nanosleep F
  clock_settime F
+ __cxa_thread_atexit_impl F
  secure_getenv F
diff --git a/ports/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/nptl/libc.abilist b/ports/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/nptl/libc.abilist
index f617405..409ca53 100644
--- a/ports/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/nptl/libc.abilist
+++ b/ports/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/nptl/libc.abilist
@@ -2087,4 +2087,5 @@ GLIBC_2.17
  clock_gettime F
  clock_nanosleep F
  clock_settime F
+ __cxa_thread_atexit_impl F
  secure_getenv F
diff --git a/ports/sysdeps/unix/sysv/linux/tile/tilepro/nptl/libc.abilist b/ports/sysdeps/unix/sysv/linux/tile/tilepro/nptl/libc.abilist
index d79b2df..41677b2 100644
--- a/ports/sysdeps/unix/sysv/linux/tile/tilepro/nptl/libc.abilist
+++ b/ports/sysdeps/unix/sysv/linux/tile/tilepro/nptl/libc.abilist
@@ -2087,4 +2087,5 @@ GLIBC_2.17
  clock_gettime F
  clock_nanosleep F
  clock_settime F
+ __cxa_thread_atexit_impl F
  secure_getenv F
diff --git a/stdlib/Makefile b/stdlib/Makefile
index 682a70c..04df5ad 100644
--- a/stdlib/Makefile
+++ b/stdlib/Makefile
@@ -33,7 +33,7 @@ routines	:=							      \
 	bsearch qsort msort						      \
 	getenv putenv setenv secure-getenv				      \
 	exit on_exit atexit cxa_atexit cxa_finalize old_atexit		      \
-	quick_exit at_quick_exit cxa_at_quick_exit			      \
+	quick_exit at_quick_exit cxa_at_quick_exit cxa_thread_atexit_impl     \
 	abs labs llabs							      \
 	div ldiv lldiv							      \
 	mblen mbstowcs mbtowc wcstombs wctomb				      \
@@ -69,9 +69,12 @@ tests		:= tst-strtol tst-strtod testmb testrand testsort testdiv   \
 		   tst-makecontext tst-strtod4 tst-strtod5 tst-qsort2	    \
 		   tst-makecontext2 tst-strtod6 tst-unsetenv1		    \
 		   tst-makecontext3 bug-getcontext bug-fmtmsg1		    \
-		   tst-secure-getenv tst-strtod-overflow tst-strtod-round
+		   tst-secure-getenv tst-strtod-overflow tst-strtod-round   \
+		   tst-tls-atexit
 tests-static	:= tst-secure-getenv
 
+modules-names	= tst-tls-atexit-lib
+
 include ../Makeconfig
 
 ifeq ($(build-shared),yes)
@@ -151,3 +154,9 @@ link-libm = $(common-objpfx)math/libm.a
 endif
 $(objpfx)bug-getcontext: $(link-libm)
 $(objpfx)tst-strtod-round: $(link-libm)
+
+tst-tls-atexit-lib.so-no-z-defs = yes
+
+LDFLAGS-tst-tls-atexit = $(common-objpfx)nptl/libpthread.so \
+			 $(common-objpfx)dlfcn/libdl.so
+$(objpfx)tst-tls-atexit.out: $(objpfx)tst-tls-atexit-lib.so
diff --git a/stdlib/Versions b/stdlib/Versions
index 250bd5f..50dec5d 100644
--- a/stdlib/Versions
+++ b/stdlib/Versions
@@ -105,6 +105,7 @@ libc {
   }
   GLIBC_2.17 {
     secure_getenv;
+    __cxa_thread_atexit_impl;
   }
   GLIBC_PRIVATE {
     # functions which have an additional interface since they are
@@ -114,5 +115,6 @@ libc {
     __abort_msg;
     # Used from other libraries
     __libc_secure_getenv;
+    __call_tls_dtors;
   }
 }
diff --git a/stdlib/cxa_thread_atexit_impl.c b/stdlib/cxa_thread_atexit_impl.c
new file mode 100644
index 0000000..4f03126
--- /dev/null
+++ b/stdlib/cxa_thread_atexit_impl.c
@@ -0,0 +1,108 @@
+/* Register destructors for C++ TLS variables declared with thread_local.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h>
+#include <ldsodefs.h>
+
+typedef void (*dtor_func) (void *);
+
+struct dtor_list
+{
+  dtor_func func;
+  void *obj;
+  struct link_map *map;
+  struct dtor_list *next;
+};
+
+static __thread struct dtor_list *tls_dtor_list;
+static __thread void *dso_handle_cache;
+static __thread struct link_map *lm_cache;
+
+/* Register a destructor for TLS variables declared with the 'thread_local'
+   keyword.  This function is only called from code generated by the C++
+   compiler.  */
+int
+__cxa_thread_atexit_impl (dtor_func func, void *obj, void *dso_handle)
+{
+  /* Prepend.  */
+  struct dtor_list *new = calloc (1, sizeof (struct dtor_list));
+  new->func = func;
+  new->obj = obj;
+  new->next = tls_dtor_list;
+  tls_dtor_list = new;
+
+  /* See if we already encountered the DSO.  */
+  __rtld_lock_lock_recursive (GL(dl_load_lock));
+
+  if (__builtin_expect (dso_handle_cache != dso_handle, 0))
+    {
+      ElfW(Addr) caller = (ElfW(Addr)) dso_handle;
+
+      /* If the address is not recognized the call comes from the main
+         program (we hope).  */
+      lm_cache = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
+
+      /* Find the highest-addressed object that DSO_HANDLE is not below.  */
+      for (Lmid_t ns = 0; ns < GL(dl_nns); ++ns)
+        for (struct link_map *l = GL(dl_ns)[ns]._ns_loaded; l != NULL;
+             l = l->l_next)
+          if (caller >= l->l_map_start && caller < l->l_map_end
+              && (l->l_contiguous || _dl_addr_inside_object (l, caller)))
+            {
+              lm_cache = l;
+              break;
+            }
+
+    }
+  /* A destructor could result in a thread_local construction and the former
+     could have cleared the flag.  */
+  if (lm_cache->l_type == lt_loaded && lm_cache->l_tls_dtor_count == 0)
+    lm_cache->l_flags_1 |= DF_1_NODELETE;
+
+  new->map = lm_cache;
+  new->map->l_tls_dtor_count++;
+
+  __rtld_lock_unlock_recursive (GL(dl_load_lock));
+
+  return 0;
+}
+
+/* Call the destructors.  This is called either when a thread returns from the
+   initial function or when the process exits via the exit(3) function.  */
+void
+__call_tls_dtors (void)
+{
+  while (tls_dtor_list)
+    {
+      struct dtor_list *cur = tls_dtor_list;
+      tls_dtor_list = tls_dtor_list->next;
+
+      cur->func (cur->obj);
+
+      __rtld_lock_lock_recursive (GL(dl_load_lock));
+
+      /* Allow DSO unload if count drops to zero.  */
+      cur->map->l_tls_dtor_count--;
+      if (cur->map->l_tls_dtor_count == 0 && cur->map->l_type == lt_loaded)
+        cur->map->l_flags_1 &= ~DF_1_NODELETE;
+
+      __rtld_lock_unlock_recursive (GL(dl_load_lock));
+
+      free (cur);
+    }
+}
diff --git a/stdlib/exit.c b/stdlib/exit.c
index 1ad548f..78cb9f5 100644
--- a/stdlib/exit.c
+++ b/stdlib/exit.c
@@ -25,7 +25,6 @@
 #include "set-hooks.h"
 DEFINE_HOOK (__libc_atexit, (void))
 
-
 /* Call all functions registered with `atexit' and `on_exit',
    in the reverse of the order in which they were registered
    perform stdio cleanup, and terminate program execution with STATUS.  */
@@ -34,6 +33,9 @@ attribute_hidden
 __run_exit_handlers (int status, struct exit_function_list **listp,
 		     bool run_list_atexit)
 {
+  /* First, call the TLS destructors.  */
+  __call_tls_dtors ();
+
   /* We do it this way to handle recursive calls to exit () made by
      the functions registered with `atexit' and `on_exit'. We call
      everyone on the list and use the status value in the last
diff --git a/stdlib/tst-tls-atexit-lib.c b/stdlib/tst-tls-atexit-lib.c
new file mode 100644
index 0000000..45ce54d
--- /dev/null
+++ b/stdlib/tst-tls-atexit-lib.c
@@ -0,0 +1,37 @@
+/* Verify that DSO is unloaded only if its TLS objects are destroyed - the DSO.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+extern void *__dso_handle;
+
+typedef struct
+{
+  void *val;
+} A;
+
+/* We only care about the destructor.  */
+void A_dtor (void *obj)
+{
+  ((A *)obj)->val = obj;
+}
+
+void do_foo (void)
+{
+  static __thread A b;
+  __cxa_thread_atexit_impl (A_dtor, &b, __dso_handle);
+}
+
diff --git a/stdlib/tst-tls-atexit.c b/stdlib/tst-tls-atexit.c
new file mode 100644
index 0000000..e973cc1
--- /dev/null
+++ b/stdlib/tst-tls-atexit.c
@@ -0,0 +1,110 @@
+/* Verify that DSO is unloaded only if its TLS objects are destroyed.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* There are two tests in this test case.  The first is implicit where it is
+   assumed that the destructor call on exit of the LOAD function does not
+   segfault.  The other is a verification that after the thread has exited, a
+   dlclose will unload the DSO.  */
+
+#include <dlfcn.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+void *handle;
+pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
+
+void *
+load (void *u)
+{
+  pthread_mutex_lock (&m);
+  handle = dlopen ("$ORIGIN/tst-tls-atexit-lib.so", RTLD_LAZY);
+  if (!handle)
+    {
+      printf ("Unable to load DSO: %s\n", dlerror ());
+      return (void *) (uintptr_t) 1;
+    }
+
+  void (*foo) (void) = (void (*) (void)) dlsym(handle, "do_foo");
+
+  if (!foo)
+    {
+      printf ("Unable to find symbol: %s\n", dlerror ());
+      exit (1);
+    }
+
+  foo ();
+
+  /* This should not unload the DSO.  If it does, then the thread exit will
+     result in a segfault.  */
+  dlclose (handle);
+  pthread_mutex_unlock (&m);
+
+  return NULL;
+}
+
+int
+main (void)
+{
+  pthread_t t;
+  int ret;
+  void *thr_ret;
+
+  if ((ret = pthread_create (&t, NULL, load, NULL)) != 0)
+    {
+      printf ("pthread_create failed: %s\n", strerror (ret));
+      return 1;
+    }
+
+  if ((ret = pthread_join (t, &thr_ret)) != 0)
+    {
+      printf ("pthread_create failed: %s\n", strerror (ret));
+      return 1;
+    }
+
+  if (thr_ret != NULL)
+    return 1;
+
+  /* Now this should unload the DSO.  */
+  dlclose (handle);
+
+  /* Run through our maps and ensure that the DSO is unloaded.  */
+  FILE *f = fopen ("/proc/self/maps", "r");
+
+  if (f == NULL)
+    {
+      perror ("Failed to open /proc/self/maps");
+      fprintf (stderr, "Skipping verification of DSO unload\n");
+      return 0;
+    }
+
+  char *line;
+  size_t s;
+  while (getline (&line, &s, f) > 0)
+    {
+      if (strstr (line, "tst-tls-atexit-lib.so"))
+        {
+	  printf ("DSO not unloaded yet:\n%s", line);
+	  return 1;
+	}
+    }
+
+  return 0;
+}
diff --git a/sysdeps/unix/sysv/linux/i386/nptl/libc.abilist b/sysdeps/unix/sysv/linux/i386/nptl/libc.abilist
index 67d5929..74cb683 100644
--- a/sysdeps/unix/sysv/linux/i386/nptl/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/nptl/libc.abilist
@@ -1818,6 +1818,7 @@ GLIBC_2.17
  clock_gettime F
  clock_nanosleep F
  clock_settime F
+ __cxa_thread_atexit_impl F
  secure_getenv F
 GLIBC_2.2
  GLIBC_2.2 A
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/nptl/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/nptl/libc.abilist
index a3cd895..b4789a8 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/nptl/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/nptl/libc.abilist
@@ -1779,6 +1779,7 @@ GLIBC_2.17
  clock_gettime F
  clock_nanosleep F
  clock_settime F
+ __cxa_thread_atexit_impl F
  secure_getenv F
  __ppc_get_timebase_freq F
 GLIBC_2.2
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/nptl/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/nptl/libc.abilist
index 0a80d0c..5571993 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/nptl/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/nptl/libc.abilist
@@ -85,6 +85,7 @@ GLIBC_2.17
  clock_gettime F
  clock_nanosleep F
  clock_settime F
+ __cxa_thread_atexit_impl F
  secure_getenv F
  __ppc_get_timebase_freq F
 GLIBC_2.3
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/nptl/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/nptl/libc.abilist
index d9914ff..29a0a03 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/nptl/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/nptl/libc.abilist
@@ -1770,6 +1770,7 @@ GLIBC_2.17
  clock_gettime F
  clock_nanosleep F
  clock_settime F
+ __cxa_thread_atexit_impl F
  secure_getenv F
 GLIBC_2.2
  GLIBC_2.2 A
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/nptl/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/nptl/libc.abilist
index ef1ead3..b707166 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/nptl/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/nptl/libc.abilist
@@ -91,6 +91,7 @@ GLIBC_2.17
  clock_gettime F
  clock_nanosleep F
  clock_settime F
+ __cxa_thread_atexit_impl F
  secure_getenv F
 GLIBC_2.2
  GLIBC_2.2 A
diff --git a/sysdeps/unix/sysv/linux/sh/nptl/libc.abilist b/sysdeps/unix/sysv/linux/sh/nptl/libc.abilist
index 733b550..9ed1ff5 100644
--- a/sysdeps/unix/sysv/linux/sh/nptl/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/nptl/libc.abilist
@@ -91,6 +91,7 @@ GLIBC_2.17
  clock_gettime F
  clock_nanosleep F
  clock_settime F
+ __cxa_thread_atexit_impl F
  secure_getenv F
 GLIBC_2.2
  GLIBC_2.2 A
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/nptl/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/nptl/libc.abilist
index 3a96ea8..ab5c04f 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/nptl/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/nptl/libc.abilist
@@ -1775,6 +1775,7 @@ GLIBC_2.17
  clock_gettime F
  clock_nanosleep F
  clock_settime F
+ __cxa_thread_atexit_impl F
  secure_getenv F
 GLIBC_2.2
  GLIBC_2.2 A
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/nptl/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/nptl/libc.abilist
index aa892b8..718607c 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/nptl/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/nptl/libc.abilist
@@ -96,6 +96,7 @@ GLIBC_2.17
  clock_gettime F
  clock_nanosleep F
  clock_settime F
+ __cxa_thread_atexit_impl F
  secure_getenv F
 GLIBC_2.2
  GLIBC_2.2 A
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/nptl/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/nptl/libc.abilist
index a42d424..8f0032e 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/nptl/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/nptl/libc.abilist
@@ -87,6 +87,7 @@ GLIBC_2.17
  clock_gettime F
  clock_nanosleep F
  clock_settime F
+ __cxa_thread_atexit_impl F
  secure_getenv F
 GLIBC_2.2.5
  GLIBC_2.2.5 A
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/nptl/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/nptl/libc.abilist
index 108b80f..fe518fe 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/nptl/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/nptl/libc.abilist
@@ -2085,4 +2085,5 @@ GLIBC_2.17
  clock_gettime F
  clock_nanosleep F
  clock_settime F
+ __cxa_thread_atexit_impl F
  secure_getenv F

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]