/* Register destructors for C++ TLS variables declared with thread_local.
- Copyright (C) 2013-2015 Free Software Foundation, Inc.
+ Copyright (C) 2013-2018 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
combinations of all three functions are the link map list, a link map for a
DSO and the link map member l_tls_dtor_count.
- __cxa_thread_atexit_impl acquires the load_lock before accessing any shared
- state and hence multiple of its instances can safely execute concurrently.
+ __cxa_thread_atexit_impl acquires the dl_load_lock before accessing any
+ shared state and hence multiple of its instances can safely execute
+ concurrently.
- _dl_close_worker acquires the load_lock before accessing any shared state as
- well and hence can concurrently execute multiple of its own instances as
+ _dl_close_worker acquires the dl_load_lock before accessing any shared state
+ as well and hence can concurrently execute multiple of its own instances as
well as those of __cxa_thread_atexit_impl safely. Not all accesses to
- l_tls_dtor_count are protected by the load lock, so we need to synchronize
- using atomics.
+ l_tls_dtor_count are protected by the dl_load_lock, so we need to
+ synchronize using atomics.
__call_tls_dtors accesses the l_tls_dtor_count without taking the lock; it
decrements the value by one. It does not need the big lock because it does
it is safe to unload the DSO. Hence, to ensure that this does not happen,
the following conditions must be met:
- 1. In _dl_close_worker, the l_tls_dtor_count load happens before the DSO
- is unload and its link map is freed
+ 1. In _dl_close_worker, the l_tls_dtor_count load happens before the DSO is
+ unloaded and its link map is freed
2. The link map dereference in __call_tls_dtors happens before the
l_tls_dtor_count dereference.
int
__cxa_thread_atexit_impl (dtor_func func, void *obj, void *dso_symbol)
{
+#ifdef PTR_MANGLE
+ PTR_MANGLE (func);
+#endif
+
/* Prepend. */
struct dtor_list *new = calloc (1, sizeof (struct dtor_list));
new->func = func;
/* This increment may only be concurrently observed either by the decrement
in __call_tls_dtors since the other l_tls_dtor_count access in
- _dl_close_worker is protected by the load lock. The execution in
+ _dl_close_worker is protected by the dl_load_lock. The execution in
__call_tls_dtors does not really depend on this value beyond the fact that
it should be atomic, so Relaxed MO should be sufficient. */
atomic_fetch_add_relaxed (&lm_cache->l_tls_dtor_count, 1);
while (tls_dtor_list)
{
struct dtor_list *cur = tls_dtor_list;
+ dtor_func func = cur->func;
+#ifdef PTR_DEMANGLE
+ PTR_DEMANGLE (func);
+#endif
tls_dtor_list = tls_dtor_list->next;
- cur->func (cur->obj);
+ func (cur->obj);
/* Ensure that the MAP dereference happens before
l_tls_dtor_count decrement. That way, we protect this access from a