about summary refs log tree commit diff
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);