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]

Re: [PATCH] Destructor support for C++11 thread_local variables


On Wed, Oct 10, 2012 at 04:20:19PM -0700, Roland McGrath wrote:
> I really hope there will be a way to use this from C, e.g.
> 
> __thread type x;
> static void __attribute__((thread_destructor (x))) foo (type *x_ptr) { ... }
> 
> I'm pretty disinclined to add features to libc whose only possible use
> is via C++.
> 
> Who says preventing DSO unloading is the right semantics?  The obvious

Unfortunately I believe that is the only possible one.

After all, that is the reason why something like that hasn't been
implemented already years ago.  You must run the dtors in the thread
where they were constructed, running them in another thread is not an option
(it can validly e.g. use all other thread_local/__thread variables that
haven't been destructed yet), and running them from async signal context
is wrong too.  All you could do to allow unloading would be to track how
many TLS dtors for each library are outstanding in each thread, and allow
dlclose when no thread contains outstanding TLS dtors for the library (with
the possible exception of current thread, those can be destructed just
fine).  That would allow dlclose for uses where all thread_local accesses
with ctors/dtors are done in threads that are pthread_joined before dlclose
(wouldn't work e.g. for OpenMP though, as that keeps some threads around
to avoid constant pthread_create/pthread_join).

BTW, the reason for not supporting ctors/dtors on plain __thread variables
as opposed to thread_local is that the mere possibility of supporting ctors
comes with significant cost (for dtors you can obviously just look at the
type of the variables if it is a class that has non-trivial dtors).
When there is:
extern thread_local int a;
int foo (void) { return a; }
in one library, and
extern int bar (void);
thread_local int a = bar ();
in another library, then a needs to be constructed on first access and thus
even the first library must check if there is a constructor of that var.
Currently G++ implements that via weak functions, where if the extern var
doesn't need an initializer, it will just look up the address of the
initializer and if it is NULL, do nothing (otherwise call it).

What we perhaps for C could do is add some new attribute,
__attribute__((tls_ctors_dtors)) or whatever, which would result in it being
treated as C++ thread_local in this regard (and some way how to specify what
the ctor/dtor for some __thread var is).

> analog to global destructors is to run them all on dlclose.  That's
> difficult to do if the semantics are that the destructor runs on the
> thread owning the variable.  (They'd be running inside a signal
> handler or something scary like that.)  It's not so hard if the
> destructor takes the specific object pointer as a parameter and might
> run on any thread.  What is supposed to happen when you dlopen an
> object defining thread_local variables with constructors when there
> are already multiple threads?

They are constructed upon first access in a particular thread.
Again, constructing upon dlopen is not an option, there could be already
many threads running at dlopen time, and we can't run the ctors in async
signal context.

The thread_local dtors aren't run upon exit in threads other than the one
calling exit (otherwise thread_local would be effectively unimplementable
if there is more than one thread still running on exit.

	Jakub


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