* elf/dl-close.c (_dl_close_worker): When removing object from
authorUlrich Drepper <drepper@redhat.com>
Sat, 19 May 2007 07:08:23 +0000 (07:08 +0000)
committerUlrich Drepper <drepper@redhat.com>
Sat, 19 May 2007 07:08:23 +0000 (07:08 +0000)
global scope, wait for all lookups to finish afterwards.
* elf/dl-open.c (add_to_global): When global scope array must
grow, allocate a new one and free old array only after all
lookups finish.
* elf/dl-runtime.c (_dl_fixup): Protect using global scope.
(_dl_lookup_symbol_x): Likewise.
* elf/dl-support.c: Define _dl_wait_lookup_done.
* sysdeps/generic/ldsodefs.h (struct rtld_global): Add
_dl_wait_lookup_done.

14 files changed:
ChangeLog
elf/dl-close.c
elf/dl-open.c
elf/dl-runtime.c
elf/dl-support.c
nptl/ChangeLog
nptl/allocatestack.c
nptl/init.c
nptl/pthreadP.h
nptl/sysdeps/i386/tls.h
nptl/sysdeps/pthread/pthread-functions.h
nptl/sysdeps/unix/sysv/linux/libc_pthread_init.c
nptl/sysdeps/x86_64/tls.h
sysdeps/generic/ldsodefs.h

index 5413c12889e2f8735e448051b0baed840a3eefa5..4de00e6a8d41e99b3b850823e77fc1ce93de9e6b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,16 @@
 2007-05-18  Ulrich Drepper  <drepper@redhat.com>
 
+       * elf/dl-close.c (_dl_close_worker): When removing object from
+       global scope, wait for all lookups to finish afterwards.
+       * elf/dl-open.c (add_to_global): When global scope array must
+       grow, allocate a new one and free old array only after all
+       lookups finish.
+       * elf/dl-runtime.c (_dl_fixup): Protect using global scope.
+       (_dl_lookup_symbol_x): Likewise.
+       * elf/dl-support.c: Define _dl_wait_lookup_done.
+       * sysdeps/generic/ldsodefs.h (struct rtld_global): Add
+       _dl_wait_lookup_done.
+
        * malloc/malloc.c (do_check_chunk): Correct check for mmaped block
        not overlapping with arena.
 
index e0fe26ad027e658e4c440e0a2e6e93f44fc0ded2..8e5c9fc03390954f80baee68aa5e4a1800ba9552 100644 (file)
@@ -31,6 +31,7 @@
 #include <sys/types.h>
 #include <sys/mman.h>
 #include <sysdep-cancel.h>
+#include <tls.h>
 
 
 /* Type of the constructor functions.  */
@@ -487,6 +488,9 @@ _dl_close_worker (struct link_map *map)
                ns_msl->r_list[cnt - 1] = ns_msl->r_list[cnt];
 
              --ns_msl->r_nlist;
+
+             if (!RTLD_SINGLE_THREAD_P)
+               THREAD_GSCOPE_WAIT ();
            }
 
          /* Remove the object from the dtv slotinfo array if it uses TLS.  */
index 583878781e2db086afceacf60d36cebd52a744bc..a043cf61b6e6b899366509c50297dab0ea79e38b 100644 (file)
@@ -32,6 +32,7 @@
 #include <bp-sym.h>
 #include <caller.h>
 #include <sysdep-cancel.h>
+#include <tls.h>
 
 #include <dl-dst.h>
 
@@ -125,15 +126,25 @@ add_to_global (struct link_map *new)
     {
       /* We have to extend the existing array of link maps in the
         main map.  */
+      struct link_map **old_global
+       = GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list;
+      size_t new_nalloc = ((ns->_ns_global_scope_alloc + to_add) * 2);
+
       new_global = (struct link_map **)
-       realloc (ns->_ns_main_searchlist->r_list,
-                ((ns->_ns_global_scope_alloc + to_add + 8)
-                 * sizeof (struct link_map *)));
+       malloc (new_nalloc * sizeof (struct link_map *));
       if (new_global == NULL)
        goto nomem;
 
-      ns->_ns_global_scope_alloc += to_add + 8;
+      memcpy (new_global, old_global,
+             ns->_ns_global_scope_alloc * sizeof (struct link_map *));
+
+      ns->_ns_global_scope_alloc = new_nalloc;
       ns->_ns_main_searchlist->r_list = new_global;
+
+      if (!RTLD_SINGLE_THREAD_P)
+       THREAD_GSCOPE_WAIT ();
+
+      free (old_global);
     }
 
   /* Now add the new entries.  */
index 9ecf62b4364c9de91b85a762dfd47a663182f604..6add5e4fffa009a9cafba2adad7e629d5afdb6b7 100644 (file)
@@ -26,6 +26,8 @@
 #include <ldsodefs.h>
 #include <sysdep-cancel.h>
 #include "dynamic-link.h"
+#include <tls.h>
+
 
 #if (!defined ELF_MACHINE_NO_RELA && !defined ELF_MACHINE_PLT_REL) \
     || ELF_MACHINE_NO_REL
@@ -97,10 +99,15 @@ _dl_fixup (
         not necessary for objects which cannot be unloaded or when
         we are not using any threads (yet).  */
       int flags = DL_LOOKUP_ADD_DEPENDENCY;
-      if (l->l_type == lt_loaded && !RTLD_SINGLE_THREAD_P)
+      if (!RTLD_SINGLE_THREAD_P)
        {
-         __rtld_mrlock_lock (l->l_scope_lock);
-         flags |= DL_LOOKUP_SCOPE_LOCK;
+         THREAD_GSCOPE_SET_FLAG ();
+
+         if (l->l_type == lt_loaded)
+           {
+             __rtld_mrlock_lock (l->l_scope_lock);
+             flags |= DL_LOOKUP_SCOPE_LOCK;
+           }
        }
 
       result = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym, l->l_scope,
@@ -109,6 +116,10 @@ _dl_fixup (
       if ((flags & DL_LOOKUP_SCOPE_LOCK) != 0)
        __rtld_mrlock_unlock (l->l_scope_lock);
 
+      /* We are done with the global scope.  */
+      if (!RTLD_SINGLE_THREAD_P)
+       THREAD_GSCOPE_RESET_FLAG ();
+
       /* Currently result contains the base load address (or link map)
         of the object that defines sym.  Now add in the symbol
         offset.  */
@@ -191,10 +202,15 @@ _dl_profile_fixup (
             not necessary for objects which cannot be unloaded or when
             we are not using any threads (yet).  */
          int flags = DL_LOOKUP_ADD_DEPENDENCY;
-         if (l->l_type == lt_loaded && !RTLD_SINGLE_THREAD_P)
+         if (!RTLD_SINGLE_THREAD_P)
            {
-             __rtld_mrlock_lock (l->l_scope_lock);
-             flags |= DL_LOOKUP_SCOPE_LOCK;
+             THREAD_GSCOPE_SET_FLAG ();
+
+             if (l->l_type == lt_loaded)
+               {
+                 __rtld_mrlock_lock (l->l_scope_lock);
+                 flags |= DL_LOOKUP_SCOPE_LOCK;
+               }
            }
 
          result = _dl_lookup_symbol_x (strtab + refsym->st_name, l,
@@ -204,6 +220,10 @@ _dl_profile_fixup (
          if ((flags & DL_LOOKUP_SCOPE_LOCK) != 0)
            __rtld_mrlock_unlock (l->l_scope_lock);
 
+         /* We are done with the global scope.  */
+         if (!RTLD_SINGLE_THREAD_P)
+           THREAD_GSCOPE_RESET_FLAG ();
+
          /* Currently result contains the base load address (or link map)
             of the object that defines sym.  Now add in the symbol
             offset.  */
index c7479dc639318c924f4b768221215264cd16e13c..cecb603ae6907b013368f2af22faf7dc20ee68ec 100644 (file)
@@ -1,5 +1,5 @@
 /* Support for dynamic linking code in static libc.
-   Copyright (C) 1996-2005, 2006 Free Software Foundation, Inc.
+   Copyright (C) 1996-2005, 2006, 2007 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
@@ -132,6 +132,9 @@ int (*_dl_make_stack_executable_hook) (void **) internal_function
   = _dl_make_stack_executable;
 
 
+/* Function in libpthread to wait for termination of lookups.  */
+void (*_dl_wait_lookup_done) (void);
+
 #ifdef NEED_DL_SYSINFO
 /* Needed for improved syscall handling on at least x86/Linux.  */
 uintptr_t _dl_sysinfo = DL_SYSINFO_DEFAULT;
index 894a9bd9fb4bcee165f2cbe07f674c50c74f8cae..db7b86f2fbac81e939e8c302759d88d402972ae6 100644 (file)
@@ -1,3 +1,16 @@
+2007-05-19  Ulrich Drepper  <drepper@redhat.com>
+
+       * allocatestack.c (__wait_lookup_done): New function.
+       * sysdeps/pthread/pthread-functions.h (struct pthread_functions):
+       Add ptr_wait_lookup_done.
+       * init.c (pthread_functions): Initialize .ptr_wait_lookup_done.
+       * pthreadP.h: Declare __wait_lookup_done.
+       * sysdeps/i386/tls.h (tcbhead_t): Add gscope_flag.
+       Define macros to implement reference handling of global scope.
+       * sysdeps/x86_64/tls.h: Likewise.
+       * sysdeps/unix/sysv/linux/libc_pthread_init.c (__libc_pthread_init):
+       Initialize GL(dl_wait_lookup_done).
+
 2007-05-17  Ulrich Drepper  <drepper@redhat.com>
 
        [BZ #4512]
index 6b60642042dc50c6f65253470ac82c81ba2b15b5..e556dbac08c8427cd0276e9c697ba97b9a7a2603 100644 (file)
@@ -996,3 +996,60 @@ __pthread_init_static_tls (struct link_map *map)
 
   lll_unlock (stack_cache_lock);
 }
+
+
+void
+attribute_hidden
+__wait_lookup_done (void)
+{
+  lll_lock (stack_cache_lock);
+
+  struct pthread *self = THREAD_SELF;
+
+  /* Iterate over the list with system-allocated threads first.  */
+  list_t *runp;
+  list_for_each (runp, &stack_used)
+    {
+      struct pthread *t = list_entry (runp, struct pthread, list);
+      if (t == self || t->header.gscope_flag == THREAD_GSCOPE_FLAG_UNUSED)
+       continue;
+
+      int *const gscope_flagp = &t->header.gscope_flag;
+
+      /* We have to wait until this thread is done with the global
+        scope.  First tell the thread that we are waiting and
+        possibly have to be woken.  */
+      if (atomic_compare_and_exchange_bool_acq (gscope_flagp,
+                                               THREAD_GSCOPE_FLAG_WAIT,
+                                               THREAD_GSCOPE_FLAG_USED))
+       continue;
+
+      do
+       lll_futex_wait (gscope_flagp, THREAD_GSCOPE_FLAG_WAIT);
+      while (*gscope_flagp == THREAD_GSCOPE_FLAG_WAIT);
+    }
+
+  /* Now the list with threads using user-allocated stacks.  */
+  list_for_each (runp, &__stack_user)
+    {
+      struct pthread *t = list_entry (runp, struct pthread, list);
+      if (t == self || t->header.gscope_flag == THREAD_GSCOPE_FLAG_UNUSED)
+       continue;
+
+      int *const gscope_flagp = &t->header.gscope_flag;
+
+      /* We have to wait until this thread is done with the global
+        scope.  First tell the thread that we are waiting and
+        possibly have to be woken.  */
+      if (atomic_compare_and_exchange_bool_acq (gscope_flagp,
+                                               THREAD_GSCOPE_FLAG_WAIT,
+                                               THREAD_GSCOPE_FLAG_USED))
+       continue;
+
+      do
+       lll_futex_wait (gscope_flagp, THREAD_GSCOPE_FLAG_WAIT);
+      while (*gscope_flagp == THREAD_GSCOPE_FLAG_WAIT);
+    }
+
+  lll_unlock (stack_cache_lock);
+}
index dddc975a5eb3635f3cab9b245caf70bf11139adc..fb4030e2490223a4252cb408b66178140adc2fe9 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+/* Copyright (C) 2002,2003,2004,2005,2006,2007 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
 #include <lowlevellock.h>
 
 
-#ifndef __NR_set_tid_address
-/* XXX For the time being...  Once we can rely on the kernel headers
-   having the definition remove these lines.  */
-#if defined __s390__
-# define __NR_set_tid_address  252
-#elif defined __ia64__
-# define __NR_set_tid_address  1233
-#elif defined __i386__
-# define __NR_set_tid_address  258
-#elif defined __x86_64__
-# define __NR_set_tid_address  218
-#elif defined __powerpc__
-# define __NR_set_tid_address  232
-#elif defined __sparc__
-# define __NR_set_tid_address  166
-#else
-# error "define __NR_set_tid_address"
-#endif
-#endif
-
-
 /* Size and alignment of static TLS block.  */
 size_t __static_tls_size;
 size_t __static_tls_align_m1;
@@ -138,7 +117,8 @@ static const struct pthread_functions pthread_functions =
     .ptr__nptl_deallocate_tsd = __nptl_deallocate_tsd,
     .ptr__nptl_setxid = __nptl_setxid,
     /* For now only the stack cache needs to be freed.  */
-    .ptr_freeres = __free_stack_cache
+    .ptr_freeres = __free_stack_cache,
+    .ptr_wait_lookup_done = __wait_lookup_done
   };
 # define ptr_pthread_functions &pthread_functions
 #else
index f9634ab0ffac97210688164b7e6acab347d66c96..21ce6fe0b7e7143363c3ee307f774c6e06ed3f47 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+/* Copyright (C) 2002,2003,2004,2005,2006,2007 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -545,6 +545,8 @@ extern int __nptl_setxid (struct xid_command *cmdp) attribute_hidden;
 
 extern void __free_stack_cache (void) attribute_hidden;
 
+extern void __wait_lookup_done (void) attribute_hidden;
+
 #ifdef SHARED
 # define PTHREAD_STATIC_FN_REQUIRE(name)
 #else
index d5b3797e69740c91651a6865753cd955ab4d4194..d9044f3fde338b3767f97a4bdcaae06f667c3a76 100644 (file)
@@ -1,5 +1,5 @@
 /* Definition for thread-local data handling.  nptl/i386 version.
-   Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+   Copyright (C) 2002,2003,2004,2005,2006,2007 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
@@ -27,6 +27,7 @@
 # include <stdint.h>
 # include <stdlib.h>
 # include <list.h>
+# include <sysdep.h>
 
 
 /* Type for the dtv.  */
@@ -51,6 +52,7 @@ typedef struct
   uintptr_t sysinfo;
   uintptr_t stack_guard;
   uintptr_t pointer_guard;
+  int gscope_flag;
 } tcbhead_t;
 
 # define TLS_MULTIPLE_THREADS_IN_TCB 1
@@ -431,6 +433,35 @@ union user_desc_init
    = THREAD_GETMEM (THREAD_SELF, header.pointer_guard))
 
 
+/* Get and set the global scope generation counter in the TCB head.  */
+#define THREAD_GSCOPE_FLAG_UNUSED 0
+#define THREAD_GSCOPE_FLAG_USED   1
+#define THREAD_GSCOPE_FLAG_WAIT   2
+#define THREAD_GSCOPE_RESET_FLAG() \
+  do                                                                         \
+    { int __res;                                                             \
+      asm volatile ("xchg %0, %%gs:%P1"                                              \
+                   : "=r" (__res)                                            \
+                   : "i" (offsetof (struct pthread, header.gscope_flag)),    \
+                     "0" (THREAD_GSCOPE_FLAG_UNUSED));                       \
+      if (__res == THREAD_GSCOPE_FLAG_WAIT)                                  \
+       lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1);                 \
+    }                                                                        \
+  while (0)
+#define THREAD_GSCOPE_SET_FLAG() \
+  THREAD_SETMEM (THREAD_SELF, header.gscope_flag, THREAD_GSCOPE_FLAG_USED)
+#ifdef PTR_DEMANGLE
+# define THREAD_GSCOPE_WAIT() \
+  do { void (*ptr) (void) = GL(dl_wait_lookup_done);                         \
+       PTR_DEMANGLE (ptr);                                                   \
+       ptr ();                                                               \
+  } while (0)
+#else
+# define THREAD_GSCOPE_WAIT() \
+  GL(dl_wait_lookup_done) ()
+#endif
+
+
 #endif /* __ASSEMBLER__ */
 
 #endif /* tls.h */
index a13b9370322457e8cbf107bed9807441f43b8a46..f0eddd30535f6e7571c66983e56df48a95f1298a 100644 (file)
@@ -97,7 +97,7 @@ struct pthread_functions
   void (*ptr__nptl_deallocate_tsd) (void);
   int (*ptr__nptl_setxid) (struct xid_command *);
   void (*ptr_freeres) (void);
-  void (*ptr_wait_lookup_done) (int);
+  void (*ptr_wait_lookup_done) (void);
 };
 
 /* Variable in libc.so.  */
index 92a188a2f3851d300c4ba178b45d01ef97964282..25509eb3d695aa5cb2f4c7c9a311b7f5456a9c9a 100644 (file)
@@ -26,6 +26,7 @@
 #include <pthreadP.h>
 #include <bits/libc-lock.h>
 #include <sysdep.h>
+#include <ldsodefs.h>
 
 
 #ifdef TLS_MULTIPLE_THREADS_IN_TCB
@@ -70,6 +71,12 @@ __libc_pthread_init (ptr, reclaim, functions)
       dest->parr[cnt] = p;
     }
   __libc_pthread_functions_init = 1;
+
+# ifdef RTLD_NOT_MANGLED
+  GL(dl_wait_lookup_done) = functions->ptr_wait_lookup_done;
+# else
+  GL(dl_wait_lookup_done) = __libc_pthread_functions.ptr_wait_lookup_done;
+# endif
 #endif
 
 #ifndef TLS_MULTIPLE_THREADS_IN_TCB
index 0b5aeb00ffe69fd09073f83025cca150fa6168ce..00c9abbfcb042965d2cf93dc2ec5b15d8d50acf9 100644 (file)
@@ -26,6 +26,7 @@
 # include <stddef.h>
 # include <stdint.h>
 # include <stdlib.h>
+# include <sysdep.h>
 
 
 /* Type for the dtv.  */
@@ -47,6 +48,7 @@ typedef struct
   dtv_t *dtv;
   void *self;          /* Pointer to the thread descriptor.  */
   int multiple_threads;
+  int gscope_flag;
   uintptr_t sysinfo;
   uintptr_t stack_guard;
   uintptr_t pointer_guard;
@@ -337,6 +339,30 @@ typedef struct
    = THREAD_GETMEM (THREAD_SELF, header.pointer_guard))
 
 
+/* Get and set the global scope generation counter in the TCB head.  */
+#define THREAD_GSCOPE_FLAG_UNUSED 0
+#define THREAD_GSCOPE_FLAG_USED   1
+#define THREAD_GSCOPE_FLAG_WAIT   2
+#define THREAD_GSCOPE_RESET_FLAG() \
+  do                                                                         \
+    { int __res;                                                             \
+      asm volatile ("xchgl %0, %%fs:%P1"                                     \
+                   : "=r" (__res)                                            \
+                   : "i" (offsetof (struct pthread, header.gscope_flag)),    \
+                     "0" (THREAD_GSCOPE_FLAG_UNUSED));                       \
+      if (__res == THREAD_GSCOPE_FLAG_WAIT)                                  \
+       lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1);                 \
+    }                                                                        \
+  while (0)
+#define THREAD_GSCOPE_SET_FLAG() \
+  THREAD_SETMEM (THREAD_SELF, header.gscope_flag, THREAD_GSCOPE_FLAG_USED)
+#define THREAD_GSCOPE_WAIT() \
+  do { void (*ptr) (void) = GL(dl_wait_lookup_done);                         \
+       PTR_DEMANGLE (ptr);                                                   \
+       ptr ();                                                               \
+  } while (0)
+
+
 #endif /* __ASSEMBLER__ */
 
 #endif /* tls.h */
index a9d20b215038b52928ed4081d825df942cb6ecfe..5205c414938b111eecb661b9286352617828614d 100644 (file)
@@ -486,6 +486,8 @@ struct rtld_global
 
   EXTERN void (*_dl_init_static_tls) (struct link_map *);
 
+  EXTERN void (*_dl_wait_lookup_done) (void);
+
 #ifdef SHARED
 };
 # define __rtld_global_attribute__