@@ -153,7 +153,11 @@ _dl_close_worker (struct link_map *map, bool force)
maps[idx] = l;
++idx;
- /* Clear DF_1_NODELETE to force object deletion. */
+ /* Clear DF_1_NODELETE to force object deletion. We don't need to touch
+ l_tls_dtor_count because forced object deletion only happens when an
+ error occurs during object load. Destructor registration for TLS
+ non-POD objects should not have happened till then for this
+ object. */
if (force)
l->l_flags_1 &= ~DF_1_NODELETE;
}
@@ -173,10 +177,13 @@ _dl_close_worker (struct link_map *map, bool force)
/* Already handled. */
continue;
+ size_t tls_dtor_count = atomic_load_relaxed (&l->l_tls_dtor_count);
+
/* Check whether this object is still used. */
if (l->l_type == lt_loaded
&& l->l_direct_opencount == 0
&& (l->l_flags_1 & DF_1_NODELETE) == 0
+ && tls_dtor_count == 0
&& !used[done_index])
continue;
@@ -50,27 +50,25 @@ __cxa_thread_atexit_impl (dtor_func func, void *obj, void *dso_symbol)
tls_dtor_list = new;
/* See if we already encountered the DSO. */
- __rtld_lock_lock_recursive (GL(dl_load_lock));
-
if (__glibc_unlikely (dso_symbol_cache != dso_symbol))
{
ElfW(Addr) caller = (ElfW(Addr)) dso_symbol;
+ /* _dl_find_dso_for_object assumes that we have the dl_load_lock. */
+ __rtld_lock_lock_recursive (GL(dl_load_lock));
struct link_map *l = _dl_find_dso_for_object (caller);
+ __rtld_lock_unlock_recursive (GL(dl_load_lock));
/* If the address is not recognized the call comes from the main
program (we hope). */
lm_cache = l ? l : GL(dl_ns)[LM_ID_BASE]._ns_loaded;
}
+
/* 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;
+ atomic_increment (&lm_cache->l_tls_dtor_count);
new->map = lm_cache;
- new->map->l_tls_dtor_count++;
-
- __rtld_lock_unlock_recursive (GL(dl_load_lock));
return 0;
}
@@ -83,19 +81,10 @@ __call_tls_dtors (void)
while (tls_dtor_list)
{
struct dtor_list *cur = tls_dtor_list;
- tls_dtor_list = tls_dtor_list->next;
+ 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));
-
+ atomic_decrement (&cur->map->l_tls_dtor_count);
free (cur);
}
}
@@ -82,7 +82,14 @@ do_test (void)
if (thr_ret != NULL)
return 1;
- /* Now this should unload the DSO. */
+ /* Now this sequence should unload the DSO. */
+ handle = dlopen ("$ORIGIN/tst-tls-atexit-lib.so", RTLD_LAZY);
+ if (!handle)
+ {
+ printf ("main thread: Unable to load DSO: %s\n", dlerror ());
+ return 1;
+ }
+
dlclose (handle);
/* Run through our maps and ensure that the DSO is unloaded. */