aboutsummaryrefslogtreecommitdiff
path: root/elf/dl-open.c
diff options
context:
space:
mode:
Diffstat (limited to 'elf/dl-open.c')
-rw-r--r--elf/dl-open.c64
1 files changed, 39 insertions, 25 deletions
diff --git a/elf/dl-open.c b/elf/dl-open.c
index cf8e8cc671..8d90b56dca 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -1,5 +1,5 @@
/* Load a shared object at runtime, relocate it, and run its initializer.
- Copyright (C) 1996-2007, 2009, 2010 Free Software Foundation, Inc.
+ Copyright (C) 1996-2007, 2009, 2010, 2011 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
@@ -347,6 +347,7 @@ dl_open_worker (void *a)
/* If the file is not loaded now as a dependency, add the search
list of the newly loaded object to the scope. */
bool any_tls = false;
+ unsigned int first_static_tls = new->l_searchlist.r_nlist;
for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
{
struct link_map *imap = new->l_searchlist.r_list[i];
@@ -425,30 +426,9 @@ dl_open_worker (void *a)
might have to increase its size. */
_dl_add_to_slotinfo (imap);
- if (imap->l_need_tls_init)
- {
- /* For static TLS we have to allocate the memory here
- and now. This includes allocating memory in the DTV.
- But we cannot change any DTV other than our own. So,
- if we cannot guarantee that there is room in the DTV
- we don't even try it and fail the load.
-
- XXX We could track the minimum DTV slots allocated in
- all threads. */
- if (! RTLD_SINGLE_THREAD_P && imap->l_tls_modid > DTV_SURPLUS)
- _dl_signal_error (0, "dlopen", NULL, N_("\
-cannot load any more object with static TLS"));
-
- imap->l_need_tls_init = 0;
-#ifdef SHARED
- /* Update the slot information data for at least the
- generation of the DSO we are allocating data for. */
- _dl_update_slotinfo (imap->l_tls_modid);
-#endif
-
- GL(dl_init_static_tls) (imap);
- assert (imap->l_need_tls_init == 0);
- }
+ if (imap->l_need_tls_init
+ && first_static_tls == new->l_searchlist.r_nlist)
+ first_static_tls = i;
/* We have to bump the generation counter. */
any_tls = true;
@@ -460,6 +440,40 @@ cannot load any more object with static TLS"));
_dl_fatal_printf (N_("\
TLS generation counter wrapped! Please report this."));
+ /* We need a second pass for static tls data, because _dl_update_slotinfo
+ must not be run while calls to _dl_add_to_slotinfo are still pending. */
+ for (unsigned int i = first_static_tls; i < new->l_searchlist.r_nlist; ++i)
+ {
+ struct link_map *imap = new->l_searchlist.r_list[i];
+
+ if (imap->l_need_tls_init
+ && ! imap->l_init_called
+ && imap->l_tls_blocksize > 0)
+ {
+ /* For static TLS we have to allocate the memory here and
+ now. This includes allocating memory in the DTV. But we
+ cannot change any DTV other than our own. So, if we
+ cannot guarantee that there is room in the DTV we don't
+ even try it and fail the load.
+
+ XXX We could track the minimum DTV slots allocated in
+ all threads. */
+ if (! RTLD_SINGLE_THREAD_P && imap->l_tls_modid > DTV_SURPLUS)
+ _dl_signal_error (0, "dlopen", NULL, N_("\
+cannot load any more object with static TLS"));
+
+ imap->l_need_tls_init = 0;
+#ifdef SHARED
+ /* Update the slot information data for at least the
+ generation of the DSO we are allocating data for. */
+ _dl_update_slotinfo (imap->l_tls_modid);
+#endif
+
+ GL(dl_init_static_tls) (imap);
+ assert (imap->l_need_tls_init == 0);
+ }
+ }
+
/* Run the initializer functions of new objects. */
_dl_init (new, args->argc, args->argv, args->env);