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]

Ping[6]: [PATCH v4] Destructor support for C++11 thread_localvariables


Ping!

On Mon, Jan 14, 2013 at 08:56:24PM +0530, Siddhesh Poyarekar wrote:
> Ping!
> 
> On Tue, Jan 08, 2013 at 03:26:27PM +0530, Siddhesh Poyarekar wrote:
> > Ping!
> > 
> > Siddhesh
> > 
> > On Fri, Dec 14, 2012 at 03:31:21PM +0530, Siddhesh Poyarekar wrote:
> > > On Thu, Nov 15, 2012 at 02:05:48PM +0530, Siddhesh Poyarekar wrote:
> > > > > http://sourceware.org/ml/libc-alpha/2012-10/msg00858.html
> > > > > 
> > > 
> > > Hi,
> > > 
> > > I've updated this patch for 2.18 along with fixes for a few problems I
> > > saw now.  I noticed that this requirement has been added to the
> > > projects list on the wiki as well:
> > > 
> > > http://sourceware.org/glibc/wiki/Development_Todo/Generic
> > > 
> > > To summarize, this patch adds destructor support for the C++11
> > > variables of the thread_local scope.  it adds a new function
> > > __cxa_thread_atexit_impl, that libstdc++ calls to register destructors
> > > for the thread_local objects it constructs.  The destructors will then
> > > be called at either thread exit or program exit.  This patch also
> > > ensures that DSOs defining thread_local objects are not unloaded till
> > > destructors of all those objects are called.  The previous thread is
> > > here:
> > > 
> > > http://sourceware.org/ml/libc-alpha/2012-10/msg00289.html
> > > 
> > > Siddhesh
> > > 
> > > 
> > > ChangeLog:
> > > 
> > > 2012-12-14  Siddhesh Poyarekar  <siddhesh@redhat.com>
> > > 
> > > 	* Versions.def: Add GLIBC_2.18.
> > > 	* 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.
> > > 
> > > ports/ChangeLog.alpha:
> > > 
> > > 2012-12-14  Siddhesh Poyarekar  <siddhesh@redhat.com>
> > > 
> > > 	* sysdeps/unix/sysv/linux/alpha/nptl/libc.abilist: Add
> > > 	__cxa_thread_atexit_impl.
> > > 
> > > ports/ChangeLog.arm:
> > > 
> > > 2012-12-14  Siddhesh Poyarekar  <siddhesh@redhat.com>
> > > 
> > > 	* sysdeps/unix/sysv/linux/arm/nptl/libc.abilist: Add
> > > 	__cxa_thread_atexit_impl.
> > > 
> > > ports/ChangeLog.ia64:
> > > 
> > > 2012-12-14  Siddhesh Poyarekar  <siddhesh@redhat.com>
> > > 
> > > 	* sysdeps/unix/sysv/linux/ia64/nptl/libc.abilist: Add
> > > 	__cxa_thread_atexit_impl.
> > > 
> > > ports/ChangeLog.m68k:
> > > 
> > > 2012-12-14  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.
> > > 
> > > ports/ChangeLog.mips:
> > > 
> > > 2012-12-14  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.
> > > 
> > > ports/ChangeLog.powerpc:
> > > 
> > > 2012-12-14  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.
> > > 
> > > ports/ChangeLog.tile:
> > > 
> > > 2012-12-14  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/Versions.def b/Versions.def
> > > index 3c9e0ae..8651992 100644
> > > --- a/Versions.def
> > > +++ b/Versions.def
> > > @@ -34,6 +34,7 @@ libc {
> > >    GLIBC_2.15
> > >    GLIBC_2.16
> > >    GLIBC_2.17
> > > +  GLIBC_2.18
> > >    HURD_CTHREADS_0.3
> > >  %ifdef EXPORT_UNWIND_FIND_FDE
> > >    GCC_3.0
> > > diff --git a/include/link.h b/include/link.h
> > > index d759064..69a3465 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..980e088 100644
> > > --- a/ports/sysdeps/unix/sysv/linux/alpha/nptl/libc.abilist
> > > +++ b/ports/sysdeps/unix/sysv/linux/alpha/nptl/libc.abilist
> > > @@ -1819,6 +1819,9 @@ GLIBC_2.17
> > >   clock_nanosleep F
> > >   clock_settime F
> > >   secure_getenv F
> > > +GLIBC_2.18
> > > + GLIBC_2.18 A
> > > + __cxa_thread_atexit_impl F
> > >  GLIBC_2.2
> > >   GLIBC_2.2 A
> > >   _IO_adjust_wcolumn F
> > > diff --git a/ports/sysdeps/unix/sysv/linux/arm/nptl/libc.abilist b/ports/sysdeps/unix/sysv/linux/arm/nptl/libc.abilist
> > > index ceab6b2..ce45208 100644
> > > --- a/ports/sysdeps/unix/sysv/linux/arm/nptl/libc.abilist
> > > +++ b/ports/sysdeps/unix/sysv/linux/arm/nptl/libc.abilist
> > > @@ -86,6 +86,9 @@ GLIBC_2.17
> > >   clock_nanosleep F
> > >   clock_settime F
> > >   secure_getenv F
> > > +GLIBC_2.18
> > > + GLIBC_2.18 A
> > > + __cxa_thread_atexit_impl F
> > >  GLIBC_2.4
> > >   GLIBC_2.4 A
> > >   _Exit F
> > > diff --git a/ports/sysdeps/unix/sysv/linux/ia64/nptl/libc.abilist b/ports/sysdeps/unix/sysv/linux/ia64/nptl/libc.abilist
> > > index b3510fe..067552d 100644
> > > --- a/ports/sysdeps/unix/sysv/linux/ia64/nptl/libc.abilist
> > > +++ b/ports/sysdeps/unix/sysv/linux/ia64/nptl/libc.abilist
> > > @@ -86,6 +86,9 @@ GLIBC_2.17
> > >   clock_nanosleep F
> > >   clock_settime F
> > >   secure_getenv F
> > > +GLIBC_2.18
> > > + GLIBC_2.18 A
> > > + __cxa_thread_atexit_impl F
> > >  GLIBC_2.2
> > >   GLIBC_2.2 A
> > >   _Exit F
> > > 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..f06cc8e 100644
> > > --- a/ports/sysdeps/unix/sysv/linux/m68k/coldfire/nptl/libc.abilist
> > > +++ b/ports/sysdeps/unix/sysv/linux/m68k/coldfire/nptl/libc.abilist
> > > @@ -87,6 +87,9 @@ GLIBC_2.17
> > >   clock_nanosleep F
> > >   clock_settime F
> > >   secure_getenv F
> > > +GLIBC_2.18
> > > + GLIBC_2.18 A
> > > + __cxa_thread_atexit_impl F
> > >  GLIBC_2.4
> > >   GLIBC_2.4 A
> > >   _Exit F
> > > 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..9010ea7 100644
> > > --- a/ports/sysdeps/unix/sysv/linux/m68k/m680x0/nptl/libc.abilist
> > > +++ b/ports/sysdeps/unix/sysv/linux/m68k/m680x0/nptl/libc.abilist
> > > @@ -1775,6 +1775,9 @@ GLIBC_2.17
> > >   clock_nanosleep F
> > >   clock_settime F
> > >   secure_getenv F
> > > +GLIBC_2.18
> > > + GLIBC_2.18 A
> > > + __cxa_thread_atexit_impl F
> > >  GLIBC_2.2
> > >   GLIBC_2.2 A
> > >   _IO_adjust_wcolumn F
> > > 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..f8cefd1 100644
> > > --- a/ports/sysdeps/unix/sysv/linux/mips/mips32/nptl/libc.abilist
> > > +++ b/ports/sysdeps/unix/sysv/linux/mips/mips32/nptl/libc.abilist
> > > @@ -2250,3 +2250,6 @@ GLIBC_2.17
> > >   clock_nanosleep F
> > >   clock_settime F
> > >   secure_getenv F
> > > +GLIBC_2.18
> > > + GLIBC_2.18 A
> > > + __cxa_thread_atexit_impl 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 df2e637..9dbbd97 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
> > > @@ -1398,6 +1398,9 @@ GLIBC_2.17
> > >   clock_nanosleep F
> > >   clock_settime F
> > >   secure_getenv F
> > > +GLIBC_2.18
> > > + GLIBC_2.18 A
> > > + __cxa_thread_atexit_impl F
> > >  GLIBC_2.2
> > >   GLIBC_2.2 A
> > >   _Exit F
> > > 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..c7e46aa 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
> > > @@ -1396,6 +1396,9 @@ GLIBC_2.17
> > >   clock_nanosleep F
> > >   clock_settime F
> > >   secure_getenv F
> > > +GLIBC_2.18
> > > + GLIBC_2.18 A
> > > + __cxa_thread_atexit_impl F
> > >  GLIBC_2.2
> > >   GLIBC_2.2 A
> > >   _Exit F
> > > 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 0efc6b5..9b6d663 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
> > > @@ -1781,6 +1781,9 @@ GLIBC_2.17
> > >   clock_nanosleep F
> > >   clock_settime F
> > >   secure_getenv F
> > > +GLIBC_2.18
> > > + GLIBC_2.18 A
> > > + __cxa_thread_atexit_impl F
> > >  GLIBC_2.2
> > >   GLIBC_2.2 A
> > >   _IO_adjust_wcolumn F
> > > 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..caf74b8 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
> > > @@ -2088,3 +2088,6 @@ GLIBC_2.17
> > >   clock_nanosleep F
> > >   clock_settime F
> > >   secure_getenv F
> > > +GLIBC_2.18
> > > + GLIBC_2.18 A
> > > + __cxa_thread_atexit_impl 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..68d975b 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
> > > @@ -2088,3 +2088,6 @@ GLIBC_2.17
> > >   clock_nanosleep F
> > >   clock_settime F
> > >   secure_getenv F
> > > +GLIBC_2.18
> > > + GLIBC_2.18 A
> > > + __cxa_thread_atexit_impl 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..caf74b8 100644
> > > --- a/ports/sysdeps/unix/sysv/linux/tile/tilepro/nptl/libc.abilist
> > > +++ b/ports/sysdeps/unix/sysv/linux/tile/tilepro/nptl/libc.abilist
> > > @@ -2088,3 +2088,6 @@ GLIBC_2.17
> > >   clock_nanosleep F
> > >   clock_settime F
> > >   secure_getenv F
> > > +GLIBC_2.18
> > > + GLIBC_2.18 A
> > > + __cxa_thread_atexit_impl F
> > > diff --git a/stdlib/Makefile b/stdlib/Makefile
> > > index 5e99d7f..20287da 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				      \
> > > @@ -70,9 +70,11 @@ tests		:= tst-strtol tst-strtod testmb testrand testsort testdiv   \
> > >  		   tst-makecontext2 tst-strtod6 tst-unsetenv1		    \
> > >  		   tst-makecontext3 bug-getcontext bug-fmtmsg1		    \
> > >  		   tst-secure-getenv tst-strtod-overflow tst-strtod-round   \
> > > -		   tst-tininess tst-strtod-underflow
> > > +		   tst-tininess tst-strtod-underflow tst-tls-atexit
> > >  tests-static	:= tst-secure-getenv
> > >  
> > > +modules-names	= tst-tls-atexit-lib
> > > +
> > >  include ../Makeconfig
> > >  
> > >  ifeq ($(build-shared),yes)
> > > @@ -154,3 +156,9 @@ $(objpfx)bug-getcontext: $(link-libm)
> > >  $(objpfx)tst-strtod-round: $(link-libm)
> > >  $(objpfx)tst-tininess: $(link-libm)
> > >  $(objpfx)tst-strtod-underflow: $(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..f1777df 100644
> > > --- a/stdlib/Versions
> > > +++ b/stdlib/Versions
> > > @@ -106,6 +106,9 @@ libc {
> > >    GLIBC_2.17 {
> > >      secure_getenv;
> > >    }
> > > +  GLIBC_2.18 {
> > > +    __cxa_thread_atexit_impl;
> > > +  }
> > >    GLIBC_PRIVATE {
> > >      # functions which have an additional interface since they are
> > >      # are cancelable.
> > > @@ -114,5 +117,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..b7312cb
> > > --- /dev/null
> > > +++ b/stdlib/tst-tls-atexit.c
> > > @@ -0,0 +1,111 @@
> > > +/* 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 = NULL;
> > > +  size_t s = 0;
> > > +  while (getline (&line, &s, f) > 0)
> > > +    {
> > > +      if (strstr (line, "tst-tls-atexit-lib.so"))
> > > +        {
> > > +	  printf ("DSO not unloaded yet:\n%s", line);
> > > +	  return 1;
> > > +	}
> > > +    }
> > > +  free (line);
> > > +
> > > +  return 0;
> > > +}
> > > diff --git a/sysdeps/unix/sysv/linux/i386/nptl/libc.abilist b/sysdeps/unix/sysv/linux/i386/nptl/libc.abilist
> > > index 67d5929..3cb314d 100644
> > > --- a/sysdeps/unix/sysv/linux/i386/nptl/libc.abilist
> > > +++ b/sysdeps/unix/sysv/linux/i386/nptl/libc.abilist
> > > @@ -1819,6 +1819,9 @@ GLIBC_2.17
> > >   clock_nanosleep F
> > >   clock_settime F
> > >   secure_getenv F
> > > +GLIBC_2.18
> > > + GLIBC_2.18 A
> > > + __cxa_thread_atexit_impl F
> > >  GLIBC_2.2
> > >   GLIBC_2.2 A
> > >   _IO_adjust_wcolumn F
> > > 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 8e45958..f27b48b 100644
> > > --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/nptl/libc.abilist
> > > +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/nptl/libc.abilist
> > > @@ -1781,6 +1781,9 @@ GLIBC_2.17
> > >   clock_nanosleep F
> > >   clock_settime F
> > >   secure_getenv F
> > > +GLIBC_2.18
> > > + GLIBC_2.18 A
> > > + __cxa_thread_atexit_impl F
> > >  GLIBC_2.2
> > >   GLIBC_2.2 A
> > >   _IO_adjust_wcolumn F
> > > diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/nptl/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/nptl/libc.abilist
> > > index 8eaaccd..195b587 100644
> > > --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/nptl/libc.abilist
> > > +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/nptl/libc.abilist
> > > @@ -87,6 +87,9 @@ GLIBC_2.17
> > >   clock_nanosleep F
> > >   clock_settime F
> > >   secure_getenv F
> > > +GLIBC_2.18
> > > + GLIBC_2.18 A
> > > + __cxa_thread_atexit_impl F
> > >  GLIBC_2.3
> > >   GLIBC_2.3 A
> > >   _Exit F
> > > 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..b6256d5 100644
> > > --- a/sysdeps/unix/sysv/linux/s390/s390-32/nptl/libc.abilist
> > > +++ b/sysdeps/unix/sysv/linux/s390/s390-32/nptl/libc.abilist
> > > @@ -1771,6 +1771,9 @@ GLIBC_2.17
> > >   clock_nanosleep F
> > >   clock_settime F
> > >   secure_getenv F
> > > +GLIBC_2.18
> > > + GLIBC_2.18 A
> > > + __cxa_thread_atexit_impl F
> > >  GLIBC_2.2
> > >   GLIBC_2.2 A
> > >   _IO_adjust_wcolumn F
> > > 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..265f66d 100644
> > > --- a/sysdeps/unix/sysv/linux/s390/s390-64/nptl/libc.abilist
> > > +++ b/sysdeps/unix/sysv/linux/s390/s390-64/nptl/libc.abilist
> > > @@ -92,6 +92,9 @@ GLIBC_2.17
> > >   clock_nanosleep F
> > >   clock_settime F
> > >   secure_getenv F
> > > +GLIBC_2.18
> > > + GLIBC_2.18 A
> > > + __cxa_thread_atexit_impl F
> > >  GLIBC_2.2
> > >   GLIBC_2.2 A
> > >   _Exit F
> > > diff --git a/sysdeps/unix/sysv/linux/sh/nptl/libc.abilist b/sysdeps/unix/sysv/linux/sh/nptl/libc.abilist
> > > index 733b550..a653292 100644
> > > --- a/sysdeps/unix/sysv/linux/sh/nptl/libc.abilist
> > > +++ b/sysdeps/unix/sysv/linux/sh/nptl/libc.abilist
> > > @@ -92,6 +92,9 @@ GLIBC_2.17
> > >   clock_nanosleep F
> > >   clock_settime F
> > >   secure_getenv F
> > > +GLIBC_2.18
> > > + GLIBC_2.18 A
> > > + __cxa_thread_atexit_impl F
> > >  GLIBC_2.2
> > >   GLIBC_2.2 A
> > >   _Exit F
> > > diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/nptl/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/nptl/libc.abilist
> > > index 3a96ea8..9defbdf 100644
> > > --- a/sysdeps/unix/sysv/linux/sparc/sparc32/nptl/libc.abilist
> > > +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/nptl/libc.abilist
> > > @@ -1776,6 +1776,9 @@ GLIBC_2.17
> > >   clock_nanosleep F
> > >   clock_settime F
> > >   secure_getenv F
> > > +GLIBC_2.18
> > > + GLIBC_2.18 A
> > > + __cxa_thread_atexit_impl F
> > >  GLIBC_2.2
> > >   GLIBC_2.2 A
> > >   _IO_adjust_wcolumn F
> > > diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/nptl/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/nptl/libc.abilist
> > > index aa892b8..35987fa 100644
> > > --- a/sysdeps/unix/sysv/linux/sparc/sparc64/nptl/libc.abilist
> > > +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/nptl/libc.abilist
> > > @@ -97,6 +97,9 @@ GLIBC_2.17
> > >   clock_nanosleep F
> > >   clock_settime F
> > >   secure_getenv F
> > > +GLIBC_2.18
> > > + GLIBC_2.18 A
> > > + __cxa_thread_atexit_impl F
> > >  GLIBC_2.2
> > >   GLIBC_2.2 A
> > >   _Exit F
> > > 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..914b590 100644
> > > --- a/sysdeps/unix/sysv/linux/x86_64/64/nptl/libc.abilist
> > > +++ b/sysdeps/unix/sysv/linux/x86_64/64/nptl/libc.abilist
> > > @@ -88,6 +88,9 @@ GLIBC_2.17
> > >   clock_nanosleep F
> > >   clock_settime F
> > >   secure_getenv F
> > > +GLIBC_2.18
> > > + GLIBC_2.18 A
> > > + __cxa_thread_atexit_impl F
> > >  GLIBC_2.2.5
> > >   GLIBC_2.2.5 A
> > >   _Exit F
> > > 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..0f64c8d 100644
> > > --- a/sysdeps/unix/sysv/linux/x86_64/x32/nptl/libc.abilist
> > > +++ b/sysdeps/unix/sysv/linux/x86_64/x32/nptl/libc.abilist
> > > @@ -2086,3 +2086,6 @@ GLIBC_2.17
> > >   clock_nanosleep F
> > >   clock_settime F
> > >   secure_getenv F
> > > +GLIBC_2.18
> > > + GLIBC_2.18 A
> > > + __cxa_thread_atexit_impl F


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