diff options
author | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2016-08-20 19:50:45 +0200 |
---|---|---|
committer | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2016-08-20 19:50:45 +0200 |
commit | 4dd9e35bfd35d3138bc44169baba098005bad51e (patch) | |
tree | a4939c43a9c3fe00eb27f023e14acc5e1fe8808c /elf/dl-close.c | |
parent | bd42a4599d1b6f77bcfe1e4f67b7cbd9e1cb2dfd (diff) | |
parent | f76453c31593957fec1a99b986bfa5506618b79c (diff) |
Merge commit 'refs/top-bases/t/bigmem' into t/bigmem
Diffstat (limited to 'elf/dl-close.c')
-rw-r--r-- | elf/dl-close.c | 78 |
1 files changed, 63 insertions, 15 deletions
diff --git a/elf/dl-close.c b/elf/dl-close.c index 5bf1de7d28..910527746e 100644 --- a/elf/dl-close.c +++ b/elf/dl-close.c @@ -1,5 +1,5 @@ /* Close a shared object opened by `_dl_open'. - Copyright (C) 1996-2014 Free Software Foundation, Inc. + Copyright (C) 1996-2015 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 @@ -33,6 +33,8 @@ #include <tls.h> #include <stap-probe.h> +#include <dl-unmap-segments.h> + /* Type of the constructor functions. */ typedef void (*fini_t) (void); @@ -73,7 +75,7 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp, /* The entry might still be in its unused state if we are closing an object that wasn't fully set up. */ - if (__builtin_expect (old_map != NULL, 1)) + if (__glibc_likely (old_map != NULL)) { assert (old_map->l_tls_modid == idx); @@ -106,7 +108,7 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp, void -_dl_close_worker (struct link_map *map) +_dl_close_worker (struct link_map *map, bool force) { /* One less direct use. */ --map->l_direct_opencount; @@ -123,7 +125,7 @@ _dl_close_worker (struct link_map *map) dl_close_state = rerun; /* There are still references to this object. Do nothing more. */ - if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0)) + if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) _dl_debug_printf ("\nclosing file=%s; direct_opencount=%u\n", map->l_name, map->l_direct_opencount); @@ -150,6 +152,14 @@ _dl_close_worker (struct link_map *map) l->l_idx = idx; maps[idx] = l; ++idx; + + /* 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; } assert (idx == nloaded); @@ -171,6 +181,9 @@ _dl_close_worker (struct link_map *map) if (l->l_type == lt_loaded && l->l_direct_opencount == 0 && (l->l_flags_1 & DF_1_NODELETE) == 0 + /* See CONCURRENCY NOTES in cxa_thread_atexit_impl.c to know why + acquire is sufficient and correct. */ + && atomic_load_acquire (&l->l_tls_dtor_count) == 0 && !used[done_index]) continue; @@ -280,7 +293,7 @@ _dl_close_worker (struct link_map *map) #ifdef SHARED /* Auditing checkpoint: we remove an object. */ - if (__builtin_expect (do_audit, 0)) + if (__glibc_unlikely (do_audit)) { struct audit_ifaces *afct = GLRO(dl_audit); for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) @@ -452,7 +465,7 @@ _dl_close_worker (struct link_map *map) #ifdef SHARED /* Auditing checkpoint: we will start deleting objects. */ - if (__builtin_expect (do_audit, 0)) + if (__glibc_unlikely (do_audit)) { struct link_map *head = ns->_ns_loaded; struct audit_ifaces *afct = GLRO(dl_audit); @@ -536,7 +549,7 @@ _dl_close_worker (struct link_map *map) object. We can unmap it. */ /* Remove the object from the dtv slotinfo array if it uses TLS. */ - if (__builtin_expect (imap->l_tls_blocksize > 0, 0)) + if (__glibc_unlikely (imap->l_tls_blocksize > 0)) { any_tls = true; @@ -633,15 +646,47 @@ _dl_close_worker (struct link_map *map) } } + /* Reset unique symbols if forced. */ + if (force) + { + struct unique_sym_table *tab = &ns->_ns_unique_sym_table; + __rtld_lock_lock_recursive (tab->lock); + struct unique_sym *entries = tab->entries; + if (entries != NULL) + { + size_t idx, size = tab->size; + for (idx = 0; idx < size; ++idx) + { + /* Clear unique symbol entries that belong to this + object. */ + if (entries[idx].name != NULL + && entries[idx].map == imap) + { + entries[idx].name = NULL; + entries[idx].hashval = 0; + tab->n_elements--; + } + } + } + __rtld_lock_unlock_recursive (tab->lock); + } + /* We can unmap all the maps at once. We determined the start address and length when we loaded the object and the `munmap' call does the rest. */ DL_UNMAP (imap); /* Finally, unlink the data structure and free it. */ - if (imap->l_prev != NULL) - imap->l_prev->l_next = imap->l_next; - else +#if DL_NNS == 1 + /* The assert in the (imap->l_prev == NULL) case gives + the compiler license to warn that NS points outside + the dl_ns array bounds in that case (as nsid != LM_ID_BASE + is tantamount to nsid >= DL_NNS). That should be impossible + in this configuration, so just assert about it instead. */ + assert (nsid == LM_ID_BASE); + assert (imap->l_prev != NULL); +#else + if (imap->l_prev == NULL) { assert (nsid != LM_ID_BASE); ns->_ns_loaded = imap->l_next; @@ -650,6 +695,9 @@ _dl_close_worker (struct link_map *map) we leave for debuggers to examine. */ r->r_map = (void *) ns->_ns_loaded; } + else +#endif + imap->l_prev->l_next = imap->l_next; --ns->_ns_nloaded; if (imap->l_next != NULL) @@ -662,7 +710,7 @@ _dl_close_worker (struct link_map *map) free (imap->l_reldeps); /* Print debugging message. */ - if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0)) + if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) _dl_debug_printf ("\nfile=%s [%lu]; destroying link map\n", imap->l_name, imap->l_ns); @@ -704,7 +752,7 @@ _dl_close_worker (struct link_map *map) /* If we removed any object which uses TLS bump the generation counter. */ if (any_tls) { - if (__builtin_expect (++GL(dl_tls_generation) == 0, 0)) + if (__glibc_unlikely (++GL(dl_tls_generation) == 0)) _dl_fatal_printf ("TLS generation counter wrapped! Please report as described in "REPORT_BUGS_TO".\n"); if (tls_free_end == GL(dl_tls_static_used)) @@ -713,7 +761,7 @@ _dl_close_worker (struct link_map *map) #ifdef SHARED /* Auditing checkpoint: we have deleted all objects. */ - if (__builtin_expect (do_audit, 0)) + if (__glibc_unlikely (do_audit)) { struct link_map *head = ns->_ns_loaded; /* Do not call the functions for any auditing object. */ @@ -757,7 +805,7 @@ _dl_close (void *_map) struct link_map *map = _map; /* First see whether we can remove the object at all. */ - if (__builtin_expect (map->l_flags_1 & DF_1_NODELETE, 0)) + if (__glibc_unlikely (map->l_flags_1 & DF_1_NODELETE)) { assert (map->l_init_called); /* Nope. Do nothing. */ @@ -770,7 +818,7 @@ _dl_close (void *_map) /* Acquire the lock. */ __rtld_lock_lock_recursive (GL(dl_load_lock)); - _dl_close_worker (map); + _dl_close_worker (map, false); __rtld_lock_unlock_recursive (GL(dl_load_lock)); } |