summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog16
-rw-r--r--elf/Makefile8
-rw-r--r--elf/dl-close.c73
-rw-r--r--elf/tst-tls7.c61
-rw-r--r--elf/tst-tlsmod1.c3
-rw-r--r--elf/tst-tlsmod2.c3
-rw-r--r--elf/tst-tlsmod3.c34
-rw-r--r--sysdeps/generic/dl-tls.c30
8 files changed, 195 insertions, 33 deletions
diff --git a/ChangeLog b/ChangeLog
index cb746f6f80..42bf1914c6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,21 @@
2002-02-13 Ulrich Drepper <drepper@redhat.com>
+ * elf/dl-close.c (remove_slotinfo): New function. Handles everything
+ for removing reference of module in slotinfo list.
+ (_dl_close): Use remove_slotinfo.
+ * sysdeps/generic/dl-tls.c: General pretty printing.
+ (oom): Define only if SHARED.
+ (_dl_next_tls_modid): Correct starting point for the case we assume
+ there is a gap. Add missing instruction grouping (doh!). Correct
+ tests for reaching maximum index.
+ * elf/Makefile: Add rules to build and run tst-tls7.
+ * elf/tst-tls7.c: New file.
+ * elf/tst-tlsmod3.c: New file.
+
+ * elf/tst-tlsmod1.c: Move #include "tls-macros.h" instead #ifdef
+ USE_TLS.
+ * elf/tst-tlsmod2.c: Likewise.
+
* elf/dl-close.c (_dl_close): When closing an object using TLS
either decrement dl_tls_max_dtv_idx or set dl_tls_dtv_gaps to
true. Increment dl_tls_generation only if we closed any TLS-using
diff --git a/elf/Makefile b/elf/Makefile
index 1a0338a600..b22f3afae3 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -119,7 +119,7 @@ tests = loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
$(tests-nodlopen-$(have-z-nodlopen)) neededtest neededtest2 \
neededtest3 neededtest4 unload2 lateglobal initfirst global \
restest2 next dblload dblunload reldep5 reldep6 tst-tls1 tst-tls2 \
- tst-tls3 tst-tls4 tst-tls5 tst-tls6
+ tst-tls3 tst-tls4 tst-tls5 tst-tls6 tst-tls7
test-srcs = tst-pathopt
tests-vis-yes = vismain
tests-nodelete-yes = nodelete
@@ -137,7 +137,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
unload2mod unload2dep ltglobmod1 ltglobmod2 pathoptobj \
dblloadmod1 dblloadmod2 dblloadmod3 reldepmod5 reldepmod6 \
reldep6mod0 reldep6mod1 reldep6mod2 reldep6mod3 reldep6mod4 \
- tst-tlsmod1 tst-tlsmod2
+ tst-tlsmod1 tst-tlsmod2 tst-tlsmod3
modules-vis-yes = vismod1 vismod2 vismod3
modules-nodelete-yes = nodelmod1 nodelmod2 nodelmod3 nodelmod4
modules-nodlopen-yes = nodlopenmod nodlopenmod2
@@ -292,6 +292,7 @@ $(objpfx)reldep6mod1.so: $(objpfx)reldep6mod0.so
$(objpfx)reldep6mod2.so: $(objpfx)reldep6mod1.so
$(objpfx)reldep6mod3.so: $(objpfx)reldep6mod2.so
$(objpfx)reldep6mod4.so: $(objpfx)reldep6mod1.so
+$(objpfx)tst-tlsmod3.so: $(objpfx)tst-tlsmod2.so
# filtmod1.so has a special rule
$(filter-out $(objpfx)filtmod1.so, $(test-modules)): $(objpfx)%.so: $(objpfx)%.os
@@ -451,3 +452,6 @@ $(objpfx)tst-tls5.out: $(objpfx)tst-tlsmod2.so
$(objpfx)tst-tls6: $(libdl)
$(objpfx)tst-tls6.out: $(objpfx)tst-tlsmod2.so
+
+$(objpfx)tst-tls7: $(libdl)
+$(objpfx)tst-tls7.out: $(objpfx)tst-tlsmod3.so
diff --git a/elf/dl-close.c b/elf/dl-close.c
index 7e7547de99..a5941268b9 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -32,6 +32,58 @@
typedef void (*fini_t) (void);
+#ifdef USE_TLS
+/* Returns true we an non-empty was found. */
+static bool
+remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp)
+{
+ if (idx - disp >= listp->len)
+ {
+ /* There must be a next entry. Otherwise would the index be wrong. */
+ assert (listp->next != NULL);
+
+ if (remove_slotinfo (idx, listp->next, disp + listp->len))
+ return true;
+
+ /* No non-empty entry. Search from the end of this elements
+ slotinfo array. */
+ idx = disp + listp->len;
+ }
+ else
+ {
+ struct link_map *old_map = listp->slotinfo[idx - disp].map;
+ assert (old_map != NULL);
+
+ /* Mark the entry as unused. */
+ listp->slotinfo[idx - disp].gen = GL(dl_tls_generation) + 1;
+ listp->slotinfo[idx - disp].map = NULL;
+
+ /* If this is not the last currently used entry no need to look
+ further. */
+ if (old_map->l_tls_modid != GL(dl_tls_max_dtv_idx))
+ return true;
+
+ assert (old_map->l_tls_modid == GL(dl_tls_max_dtv_idx));
+ }
+
+ while (idx - disp > disp == 0 ? 1 + GL(dl_tls_static_nelem) : 0)
+ {
+ --idx;
+
+ if (listp->slotinfo[idx - disp].map != NULL)
+ {
+ /* Found a new last used index. */
+ GL(dl_tls_max_dtv_idx) = idx;
+ return true;
+ }
+ }
+
+ /* No non-entry in this list element. */
+ return false;
+}
+#endif
+
+
void
internal_function
_dl_close (void *_map)
@@ -214,25 +266,12 @@ _dl_close (void *_map)
TLS. */
if (__builtin_expect (imap->l_tls_blocksize > 0, 0))
{
- /* Locate the entry in the slotinfo array. */
- size_t idx = imap->l_tls_modid;
- struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list);
-
- while (idx >= listp->len)
- {
- idx -= listp->len;
- listp = listp->next;
- }
-
- listp->slotinfo[idx].gen = GL(dl_tls_generation) + 1;
- listp->slotinfo[idx].map = NULL;
-
any_tls = true;
- if (imap->l_tls_modid == GL(dl_tls_max_dtv_idx))
- --GL(dl_tls_max_dtv_idx);
- else
- GL(dl_tls_dtv_gaps) = true;
+ if (! remove_slotinfo (imap->l_tls_modid,
+ GL(dl_tls_dtv_slotinfo_list), 0))
+ /* All dynamically loaded modules with TLS are unloaded. */
+ GL(dl_tls_max_dtv_idx) = GL(dl_tls_static_nelem);
}
#endif
diff --git a/elf/tst-tls7.c b/elf/tst-tls7.c
new file mode 100644
index 0000000000..4f785fe78e
--- /dev/null
+++ b/elf/tst-tls7.c
@@ -0,0 +1,61 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <link.h>
+#include <tls.h>
+
+
+#define TEST_FUNCTION do_test ()
+static int
+do_test (void)
+{
+#ifdef USE_TLS
+ static const char modname[] = "tst-tlsmod3.so";
+ int result = 0;
+ int (*fp) (void);
+ void *h;
+ int i;
+ int modid = -1;
+
+ for (i = 0; i < 10; ++i)
+ {
+ h = dlopen (modname, RTLD_LAZY);
+ if (h == NULL)
+ {
+ printf ("cannot open '%s': %s\n", modname, dlerror ());
+ exit (1);
+ }
+
+ /* Dirty test code here: we peek into a private data structure.
+ We make sure that the module gets assigned the same ID every
+ time. The value of the first round is used. */
+ if (modid == -1)
+ modid = ((struct link_map *) h)->l_tls_modid;
+ else if (((struct link_map *) h)->l_tls_modid != modid)
+ {
+ printf ("round %d: modid now %d, initially %d\n",
+ i, ((struct link_map *) h)->l_tls_modid, modid);
+ result = 1;
+ }
+
+ fp = dlsym (h, "in_dso2");
+ if (fp == NULL)
+ {
+ printf ("cannot get symbol 'in_dso2': %s\n", dlerror ());
+ exit (1);
+ }
+
+ result |= fp ();
+
+ dlclose (h);
+ }
+
+ return result;
+#else
+ return 0;
+#endif
+}
+
+
+#include "../test-skeleton.c"
diff --git a/elf/tst-tlsmod1.c b/elf/tst-tlsmod1.c
index cca8df6549..7e768a6593 100644
--- a/elf/tst-tlsmod1.c
+++ b/elf/tst-tlsmod1.c
@@ -1,10 +1,11 @@
#include <stdio.h>
#include <tls.h>
+
+#ifdef USE_TLS
#include "tls-macros.h"
-#ifdef USE_TLS
/* One define int variable, two externs. */
COMMON_INT_DEF(foo);
VAR_INT_DEF(bar);
diff --git a/elf/tst-tlsmod2.c b/elf/tst-tlsmod2.c
index 30ed67163d..6aec8120c0 100644
--- a/elf/tst-tlsmod2.c
+++ b/elf/tst-tlsmod2.c
@@ -1,9 +1,10 @@
#include <stdio.h>
#include <tls.h>
-#include "tls-macros.h"
#ifdef USE_TLS
+#include "tls-macros.h"
+
COMMON_INT_DEF(foo);
diff --git a/elf/tst-tlsmod3.c b/elf/tst-tlsmod3.c
new file mode 100644
index 0000000000..ff4a4460b9
--- /dev/null
+++ b/elf/tst-tlsmod3.c
@@ -0,0 +1,34 @@
+#include <stdio.h>
+
+#include <tls.h>
+#include "tls-macros.h"
+
+#ifdef USE_TLS
+extern int in_dso (int n, int *caller_foop);
+
+COMMON_INT_DEF(comm_n);
+
+
+
+
+int
+in_dso2 (void)
+{
+ int *foop = TLS_GD (foo);
+ int result = 0;
+ static int n;
+ int *np = TLS_GD (comm_n);
+
+ if (n != *np)
+ {
+ printf ("n = %d != comm_n = %d\n", n, *np);
+ result = 1;
+ }
+
+ result |= in_dso (*foop = 42 + n++, foop);
+
+ *foop = 16;
+
+ return result;
+}
+#endif
diff --git a/sysdeps/generic/dl-tls.c b/sysdeps/generic/dl-tls.c
index d13b0f93fa..7e45850198 100644
--- a/sysdeps/generic/dl-tls.c
+++ b/sysdeps/generic/dl-tls.c
@@ -29,14 +29,15 @@
/* We don't need any of this if TLS is not supported. */
#ifdef USE_TLS
-#include <dl-tls.h>
-#include <ldsodefs.h>
+# include <dl-tls.h>
+# include <ldsodefs.h>
/* Value used for dtv entries for which the allocation is delayed. */
# define TLS_DTV_UNALLOCATED ((void *) -1l)
/* Out-of-memory handler. */
+# ifdef SHARED
static void
__attribute__ ((__noreturn__))
oom (void)
@@ -52,11 +53,12 @@ cannot allocate memory for thread-local data: ABORT\n";
/* Just in case something goes wrong with the kill. */
while (1)
{
-# ifdef ABORT_INSTRUCTION
+# ifdef ABORT_INSTRUCTION
ABORT_INSTRUCTION;
-# endif
+# endif
}
}
+# endif
@@ -75,16 +77,20 @@ _dl_next_tls_modid (void)
start since there are no gaps at that time. Therefore it
does not matter that the dl_tls_dtv_slotinfo is not allocated
yet when the function is called for the first times. */
- result = GL(dl_tls_static_nelem);
- assert (result < GL(dl_tls_max_dtv_idx));
+ result = GL(dl_tls_static_nelem) + 1;
+ /* If the following would not be true we mustn't have assumed
+ there is a gap. */
+ assert (result <= GL(dl_tls_max_dtv_idx));
do
{
while (result - disp < runp->len)
- if (runp->slotinfo[result - disp].map == NULL)
- break;
+ {
+ if (runp->slotinfo[result - disp].map == NULL)
+ break;
- ++result;
- assert (result <= GL(dl_tls_max_dtv_idx) + 1);
+ ++result;
+ assert (result <= GL(dl_tls_max_dtv_idx) + 1);
+ }
if (result - disp < runp->len)
break;
@@ -93,11 +99,11 @@ _dl_next_tls_modid (void)
}
while ((runp = runp->next) != NULL);
- if (result >= GL(dl_tls_max_dtv_idx) + 1)
+ if (result >= GL(dl_tls_max_dtv_idx))
{
/* The new index must indeed be exactly one higher than the
previous high. */
- assert (result == GL(dl_tls_max_dtv_idx) + 1);
+ assert (result == GL(dl_tls_max_dtv_idx));
/* There is no gap anymore. */
GL(dl_tls_dtv_gaps) = false;