summaryrefslogtreecommitdiff
path: root/elf/dl-close.c
diff options
context:
space:
mode:
authorSamuel Thibault <samuel.thibault@ens-lyon.org>2016-08-20 19:50:45 +0200
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2016-08-20 19:50:45 +0200
commit4dd9e35bfd35d3138bc44169baba098005bad51e (patch)
treea4939c43a9c3fe00eb27f023e14acc5e1fe8808c /elf/dl-close.c
parentbd42a4599d1b6f77bcfe1e4f67b7cbd9e1cb2dfd (diff)
parentf76453c31593957fec1a99b986bfa5506618b79c (diff)
Merge commit 'refs/top-bases/t/bigmem' into t/bigmem
Diffstat (limited to 'elf/dl-close.c')
-rw-r--r--elf/dl-close.c78
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));
}