]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
2007-06-09 Ulrich Drepper <drepper@redhat.com>
authorJakub Jelinek <jakub@redhat.com>
Thu, 12 Jul 2007 15:33:46 +0000 (15:33 +0000)
committerJakub Jelinek <jakub@redhat.com>
Thu, 12 Jul 2007 15:33:46 +0000 (15:33 +0000)
* elf/do-lookup.h (do_lookup_x): Read r_nlist before r_list and
make sure gcc doesn't mess around with this.

2007-06-08  Ulrich Drepper  <drepper@redhat.com>

* elf/dl-lookup.c (_dl_lookup_symbol_x): Remove use of r_nlist.

2007-06-08  Jakub Jelinek  <jakub@redhat.com>

* elf/dl-close.c (_dl_close_worker): Remove all to be removed
libraries from the global scope at once and call THREAD_GSCOPE_WAIT
at most once per _dl_close_worker.

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.

2007-05-11  Ulrich Drepper  <drepper@redhat.com>

* elf/dl-close.c (_dl_close_worker): Help gcc to optimize by
adding new variables.

* elf/dl-open.c (add_to_global): Introduce variable ns to help gcc
optimize.  Completely extend global scope array before making the
new entries visible.

2007-01-15  Ulrich Drepper  <drepper@redhat.com>

* sysdeps/generic/ldsodefs.h: Define DL_LOOKUP_SCOPE_LOCK.
* elf/dl-lookup.c (add_dependency): If scope map is locked, unlock
it before getting dl_load_lock and then relock.
(_dl_lookup_symbol_x): Pass flags to add_dependency.
When rerunning _dl_lookup_symbol_x, compute symbol_scope again in
case we unlocked the scope.
* elf/dl-runtime.c (_dl_fixup): Pass DL_LOOKUP_SCOPE_LOCK to
_dl_lookup_symbol_x in case we locked the scope.
(_dl_profile_fixup): Likewise.
* elf/dl-sym.c (do_sym): In flags passed to call_dl_lookup, also
set DL_LOOKUP_SCOPE_LOCK.

2006-10-29  Jakub Jelinek  <jakub@redhat.com>

* elf/dl-sym.c (do_sym): Use RTLD_SINGLE_THREAD_P.
* elf/dl-runtime.c (_dl_fixup, _dl_profile_fixup): Likewise.
* elf/dl-close.c (_dl_close_worker): Likewise.
* elf/dl-open.c (_dl_open_worker): Likewise.
* sysdeps/generic/sysdep-cancel.h (RTLD_SINGLE_THREAD_P): Define.

2006-10-27  Jakub Jelinek  <jakub@redhat.com>

* elf/dl-lookup.c (_dl_debug_bindings): Remove unused symbol_scope
argument.
(_dl_lookup_symbol_x): Adjust caller.

* sysdeps/generic/ldsodefs.h (struct link_namespaces): Remove
_ns_global_scope.
* elf/rtld.c (dl_main): Don't initialize _ns_global_scope.

* elf/dl-libc.c: Revert l_scope name changes.
* elf/dl-load.c: Likewise.
* elf/dl-object.c: Likewise.
* elf/rtld.c: Likewise.
* elf/dl-close.c (_dl_close): Likewise.
* elf/dl-open.c (dl_open_worker): Likewise.  If not SINGLE_THREAD_P,
always use __rtld_mrlock_{change,done}.  Always free old scope list
here if not l_scope_mem.
* elf/dl-runtime.c (_dl_fixup, _dl_profile_fixup): Revert l_scope name
change.  Never free scope list here.  Just __rtld_mrlock_lock before
the lookup and __rtld_mrlock_unlock it after the lookup.
* elf/dl-sym.c: Likewise.
* include/link.h (struct r_scoperec): Remove.
(struct link_map): Replace l_scoperec with l_scope, l_scoperec_mem
with l_scope_mem and l_scoperec_lock with l_scope_lock.

2006-10-18  Ulrich Drepper  <drepper@redhat.com>

* elf/dl-lookup.c (_dl_lookup_symbol_x): Add warning to
_dl_lookup_symbol_x code.

2006-10-17  Jakub Jelinek  <jakub@redhat.com>

* elf/dl-runtime.c: Include sysdep-cancel.h.
(_dl_fixup, _dl_profile_fixup): Use __rtld_mrlock_* and
scoperec->nusers only if !SINGLE_THREAD_P.
* elf/dl-sym.c: Include sysdep-cancel.h.
(do_sym): Use __rtld_mrlock_* and scoperec->nusers only
if !SINGLE_THREAD_P.
* elf/dl-close.c: Include sysdep-cancel.h.
(_dl_close): Use __rtld_mrlock_* and scoperec->nusers only
if !SINGLE_THREAD_P.
* elf/dl-open.c: Include sysdep-cancel.h.
(dl_open_worker): Use __rtld_mrlock_* and scoperec->nusers only
if !SINGLE_THREAD_P.

2006-10-09  Ulrich Drepper  <drepper@redhat.com>
    Jakub Jelinek  <jakub@redhat.com>

Implement reference counting of scope records.
* elf/dl-close.c (_dl_close): Remove all scopes from removed objects
from the list in objects which remain.  Always allocate new scope
record.
* elf/dl-open.c (dl_open_worker): When growing array for scopes,
don't resize, allocate a new one.
* elf/dl-runtime.c: Update reference counters before using a scope
array.
* elf/dl-sym.c: Likewise.
* elf/dl-libc.c: Adjust for l_scope name change.
* elf/dl-load.c: Likewise.
* elf/dl-object.c: Likewise.
* elf/rtld.c: Likewise.
* include/link.h: Include <rtld-lowlevel.h>.  Define struct
r_scoperec.  Replace r_scope with pointer to r_scoperec structure.
Add l_scoperec_lock.
* sysdeps/generic/ldsodefs.h: Include <rtld-lowlevel.h>.
* sysdeps/generic/rtld-lowlevel.h: New file.
nptl/
2007-05-28  Jakub Jelinek  <jakub@redhat.com>

* sysdeps/i386/tls.h (THREAD_GSCOPE_RESET_FLAG): Use explicit
insn suffix.
(THREAD_GSCOPE_GET_FLAG): Remove.
* sysdeps/x86_64/tls.h (THREAD_GSCOPE_GET_FLAG): Remove.
* allocatestack.c (__wait_lookup_done): Revert 2007-05-24
changes.
* sysdeps/powerpc/tls.h (tcbhead_t): Remove gscope_flag.
(THREAD_GSCOPE_GET_FLAG): Remove.
(THREAD_GSCOPE_RESET_FLAG): Use THREAD_SELF->header.gscope_flag
instead of THREAD_GSCOPE_GET_FLAG.
(THREAD_GSCOPE_SET_FLAG): Likewise.  Add atomic_write_barrier after
it.
* sysdeps/s390/tls.h (THREAD_GSCOPE_FLAG_UNUSED,
THREAD_GSCOPE_FLAG_USED, THREAD_GSCOPE_FLAG_WAIT,
THREAD_GSCOPE_RESET_FLAG, THREAD_GSCOPE_SET_FLAG,
THREAD_GSCOPE_WAIT): Define.
* sysdeps/sparc/tls.h (THREAD_GSCOPE_FLAG_UNUSED,
THREAD_GSCOPE_FLAG_USED, THREAD_GSCOPE_FLAG_WAIT,
THREAD_GSCOPE_RESET_FLAG, THREAD_GSCOPE_SET_FLAG,
THREAD_GSCOPE_WAIT): Define.
* sysdeps/sh/tls.h (THREAD_GSCOPE_FLAG_UNUSED,
THREAD_GSCOPE_FLAG_USED, THREAD_GSCOPE_FLAG_WAIT,
THREAD_GSCOPE_RESET_FLAG, THREAD_GSCOPE_SET_FLAG,
THREAD_GSCOPE_WAIT): Define.
* sysdeps/ia64/tls.h (THREAD_GSCOPE_FLAG_UNUSED,
THREAD_GSCOPE_FLAG_USED, THREAD_GSCOPE_FLAG_WAIT,
THREAD_GSCOPE_RESET_FLAG, THREAD_GSCOPE_SET_FLAG,
THREAD_GSCOPE_WAIT): Define.

2007-05-24  Richard Henderson  <rth@redhat.com>

* descr.h (struct pthread): Add header.gscope_flag.
* sysdeps/alpha/tls.h (THREAD_GSCOPE_FLAG_UNUSED,
THREAD_GSCOPE_FLAG_USED, THREAD_GSCOPE_FLAG_WAIT,
THREAD_GSCOPE_RESET_FLAG, THREAD_GSCOPE_SET_FLAG,
THREAD_GSCOPE_WAIT): Define.

2007-05-26  Ulrich Drepper  <drepper@redhat.com>

* allocatestack.c: Revert last change.
* init.c: Likewise.
* sysdeps/i386/tls.h: Likewise.
* sysdeps/x86_64/tls.h: Likewise.

2007-05-24  Jakub Jelinek  <jakub@redhat.com>

* sysdeps/powerpc/tls.h (tcbhead_t): Add gscope_flag.
(THREAD_GSCOPE_FLAG_UNUSED, THREAD_GSCOPE_FLAG_USED,
THREAD_GSCOPE_FLAG_WAIT): Define.
(THREAD_GSCOPE_GET_FLAG, THREAD_GSCOPE_SET_FLAG,
THREAD_GSCOPE_RESET_FLAG, THREAD_GSCOPE_WAIT): Define.
* sysdeps/i386/tls.h (THREAD_GSCOPE_WAIT): Don't use
PTR_DEMANGLE.
(THREAD_GSCOPE_GET_FLAG): Define.
* sysdeps/x86_64/tls.h (THREAD_GSCOPE_GET_FLAG): Define.
* allocatestack.c (__wait_lookup_done): Use THREAD_GSCOPE_GET_FLAG
instead of ->header.gscope_flag directly.

2007-05-21  Ulrich Drepper  <drepper@redhat.com>

* sysdeps/pthread/pthread-functions.h (struct pthread_functions):
Remove ptr_wait_lookup_done again.
* init.c (pthread_functions): Don't add .ptr_wait_lookup_done here.
(__pthread_initialize_minimal_internal): Initialize
_dl_wait_lookup_done pointer in _rtld_global directly.
* sysdeps/unix/sysv/linux/libc_pthread_init.c (__libc_pthread_init):
Remove code to code _dl_wait_lookup_done.
* sysdeps/x86_64/tls.h (THREAD_GSCOPE_WAIT): The pointer is not
encrypted for now.

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).

2006-12-09  Ulrich Drepper  <drepper@redhat.com>

* sysdeps/unix/sysv/linux/rtld-lowlevel.h
(__rtld_mrlock_initialize): Add missing closing parenthesis.

2006-10-29  Jakub Jelinek  <jakub@redhat.com>

* sysdeps/unix/sysv/linux/i386/sysdep-cancel.h (RTLD_SINGLE_THREAD_P):
Define.
(SINGLE_THREAD_P): Define to 1 if IS_IN_rtld.
* sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h: Likewise.
* sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h: Likewise.
* sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h: Likewise.
* sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h: Likewise.
* sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h: Likewise.
* sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h: Likewise.
* sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h: Likewise.
* sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h: Likewise.
* sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h: Likewise.
* sysdeps/unix/sysv/linux/sh/sysdep-cancel.h: Likewise.

2006-10-27  Jakub Jelinek  <jakub@redhat.com>

* sysdeps/unix/sysv/linux/rtld-lowlevel.h (__rtld_mrlock_lock,
__rtld_mrlock_change): Update oldval if atomic compare and exchange
failed.

* sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h (SINGLE_THREAD_P):
Define to THREAD_SELF->header.multiple_threads.
* sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h (SINGLE_THREAD_P):
Likewise.
* sysdeps/unix/sysv/linux/i386/sysdep-cancel.h (SINGLE_THREAD_P):
Likewise.
* sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h
(SINGLE_THREAD_P): Likewise.
* sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h
(SINGLE_THREAD_P): Likewise.
* sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h
(SINGLE_THREAD_P): Likewise.
* sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h
(SINGLE_THREAD_P): Likewise.
* sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h (SINGLE_THREAD_P):
Likewise.
* sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h
(SINGLE_THREAD_P): Likewise.
* sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h
(SINGLE_THREAD_P): Likewise.
* sysdeps/unix/sysv/linux/sh/sysdep-cancel.h (SINGLE_THREAD_P):
Likewise.

2006-10-09  Ulrich Drepper  <drepper@redhat.com>

* sysdeps/unix/sysv/linux/rtld-lowlevel.h: New file..

38 files changed:
ChangeLog
elf/dl-close.c
elf/dl-lookup.c
elf/dl-object.c
elf/dl-open.c
elf/dl-runtime.c
elf/dl-support.c
elf/dl-sym.c
elf/do-lookup.h
elf/rtld.c
include/link.h
nptl/ChangeLog
nptl/allocatestack.c
nptl/descr.h
nptl/init.c
nptl/pthreadP.h
nptl/sysdeps/alpha/tls.h
nptl/sysdeps/i386/tls.h
nptl/sysdeps/ia64/tls.h
nptl/sysdeps/powerpc/tls.h
nptl/sysdeps/s390/tls.h
nptl/sysdeps/sh/tls.h
nptl/sysdeps/sparc/tls.h
nptl/sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h
nptl/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h
nptl/sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h
nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h
nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h
nptl/sysdeps/unix/sysv/linux/rtld-lowlevel.h [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h
nptl/sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h
nptl/sysdeps/unix/sysv/linux/sh/sysdep-cancel.h
nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h
nptl/sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h
nptl/sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h
nptl/sysdeps/x86_64/tls.h
sysdeps/generic/ldsodefs.h
sysdeps/generic/sysdep-cancel.h

index 94664d408cc885caf05923e3e7e0287b054cbfaf..2d68390de5aece04eb537325002e880ca5bd263c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,130 @@
+2007-06-09  Ulrich Drepper  <drepper@redhat.com>
+
+       * elf/do-lookup.h (do_lookup_x): Read r_nlist before r_list and
+       make sure gcc doesn't mess around with this.
+
+2007-06-08  Ulrich Drepper  <drepper@redhat.com>
+
+       * elf/dl-lookup.c (_dl_lookup_symbol_x): Remove use of r_nlist.
+
+2007-06-08  Jakub Jelinek  <jakub@redhat.com>
+
+       * elf/dl-close.c (_dl_close_worker): Remove all to be removed
+       libraries from the global scope at once and call THREAD_GSCOPE_WAIT
+       at most once per _dl_close_worker.
+
+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.
+
+2007-05-11  Ulrich Drepper  <drepper@redhat.com>
+
+       * elf/dl-close.c (_dl_close_worker): Help gcc to optimize by
+       adding new variables.
+
+       * elf/dl-open.c (add_to_global): Introduce variable ns to help gcc
+       optimize.  Completely extend global scope array before making the
+       new entries visible.
+
+2007-01-15  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/generic/ldsodefs.h: Define DL_LOOKUP_SCOPE_LOCK.
+       * elf/dl-lookup.c (add_dependency): If scope map is locked, unlock
+       it before getting dl_load_lock and then relock.
+       (_dl_lookup_symbol_x): Pass flags to add_dependency.
+       When rerunning _dl_lookup_symbol_x, compute symbol_scope again in
+       case we unlocked the scope.
+       * elf/dl-runtime.c (_dl_fixup): Pass DL_LOOKUP_SCOPE_LOCK to
+       _dl_lookup_symbol_x in case we locked the scope.
+       (_dl_profile_fixup): Likewise.
+       * elf/dl-sym.c (do_sym): In flags passed to call_dl_lookup, also
+       set DL_LOOKUP_SCOPE_LOCK.
+
+2006-10-29  Jakub Jelinek  <jakub@redhat.com>
+
+       * elf/dl-sym.c (do_sym): Use RTLD_SINGLE_THREAD_P.
+       * elf/dl-runtime.c (_dl_fixup, _dl_profile_fixup): Likewise.
+       * elf/dl-close.c (_dl_close_worker): Likewise.
+       * elf/dl-open.c (_dl_open_worker): Likewise.
+       * sysdeps/generic/sysdep-cancel.h (RTLD_SINGLE_THREAD_P): Define.
+
+2006-10-27  Jakub Jelinek  <jakub@redhat.com>
+
+       * elf/dl-lookup.c (_dl_debug_bindings): Remove unused symbol_scope
+       argument.
+       (_dl_lookup_symbol_x): Adjust caller.
+
+       * sysdeps/generic/ldsodefs.h (struct link_namespaces): Remove
+       _ns_global_scope.
+       * elf/rtld.c (dl_main): Don't initialize _ns_global_scope.
+
+       * elf/dl-libc.c: Revert l_scope name changes.
+       * elf/dl-load.c: Likewise.
+       * elf/dl-object.c: Likewise.
+       * elf/rtld.c: Likewise.
+       * elf/dl-close.c (_dl_close): Likewise.
+       * elf/dl-open.c (dl_open_worker): Likewise.  If not SINGLE_THREAD_P,
+       always use __rtld_mrlock_{change,done}.  Always free old scope list
+       here if not l_scope_mem.
+       * elf/dl-runtime.c (_dl_fixup, _dl_profile_fixup): Revert l_scope name
+       change.  Never free scope list here.  Just __rtld_mrlock_lock before
+       the lookup and __rtld_mrlock_unlock it after the lookup.
+       * elf/dl-sym.c: Likewise.
+       * include/link.h (struct r_scoperec): Remove.
+       (struct link_map): Replace l_scoperec with l_scope, l_scoperec_mem
+       with l_scope_mem and l_scoperec_lock with l_scope_lock.
+
+2006-10-18  Ulrich Drepper  <drepper@redhat.com>
+
+       * elf/dl-lookup.c (_dl_lookup_symbol_x): Add warning to
+       _dl_lookup_symbol_x code.
+
+2006-10-17  Jakub Jelinek  <jakub@redhat.com>
+
+       * elf/dl-runtime.c: Include sysdep-cancel.h.
+       (_dl_fixup, _dl_profile_fixup): Use __rtld_mrlock_* and
+       scoperec->nusers only if !SINGLE_THREAD_P.
+       * elf/dl-sym.c: Include sysdep-cancel.h.
+       (do_sym): Use __rtld_mrlock_* and scoperec->nusers only
+       if !SINGLE_THREAD_P.
+       * elf/dl-close.c: Include sysdep-cancel.h.
+       (_dl_close): Use __rtld_mrlock_* and scoperec->nusers only
+       if !SINGLE_THREAD_P.
+       * elf/dl-open.c: Include sysdep-cancel.h.
+       (dl_open_worker): Use __rtld_mrlock_* and scoperec->nusers only
+       if !SINGLE_THREAD_P.
+
+2006-10-09  Ulrich Drepper  <drepper@redhat.com>
+           Jakub Jelinek  <jakub@redhat.com>
+
+       Implement reference counting of scope records.
+       * elf/dl-close.c (_dl_close): Remove all scopes from removed objects
+       from the list in objects which remain.  Always allocate new scope
+       record.
+       * elf/dl-open.c (dl_open_worker): When growing array for scopes,
+       don't resize, allocate a new one.
+       * elf/dl-runtime.c: Update reference counters before using a scope
+       array.
+       * elf/dl-sym.c: Likewise.
+       * elf/dl-libc.c: Adjust for l_scope name change.
+       * elf/dl-load.c: Likewise.
+       * elf/dl-object.c: Likewise.
+       * elf/rtld.c: Likewise.
+       * include/link.h: Include <rtld-lowlevel.h>.  Define struct
+       r_scoperec.  Replace r_scope with pointer to r_scoperec structure.
+       Add l_scoperec_lock.
+       * sysdeps/generic/ldsodefs.h: Include <rtld-lowlevel.h>.
+       * sysdeps/generic/rtld-lowlevel.h: New file.
+
 2007-06-06  Jakub Jelinek  <jakub@redhat.com>
 
        [BZ #4586]
        * nis/nis_xdr.c: Avoid some function calls.
 
 2006-08-07  Jakub Jelinek  <jakub@redhat.com>
-            Ulrich Drepper  <drepper@redhat.com>
+           Ulrich Drepper  <drepper@redhat.com>
 
        * nis/nis_call.c (rec_dirsearch) [case LOWER_NAME]: Don't take
        short cut if only one name component is stripped away.
index cc7a9b3213501b5f292c28e1944179a1da685c5c..b20e5f841509f64e16f172f5e86b944c7b912c9e 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <assert.h>
 #include <dlfcn.h>
+#include <errno.h>
 #include <libintl.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <ldsodefs.h>
 #include <sys/types.h>
 #include <sys/mman.h>
+#include <sysdep-cancel.h>
+#include <tls.h>
 
 
 /* Type of the constructor functions.  */
 typedef void (*fini_t) (void);
 
 
+/* Special l_idx value used to indicate which objects remain loaded.  */
+#define IDX_STILL_USED -1
+
+
 #ifdef USE_TLS
 /* Returns true we an non-empty was found.  */
 static bool
@@ -103,8 +110,6 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp,
 void
 _dl_close_worker (struct link_map *map)
 {
-  Lmid_t ns = map->l_ns;
-
   /* One less direct use.  */
   --map->l_direct_opencount;
 
@@ -127,13 +132,16 @@ _dl_close_worker (struct link_map *map)
       return;
     }
 
+  Lmid_t nsid = map->l_ns;
+  struct link_namespaces *ns = &GL(dl_ns)[nsid];
+
  retry:
   dl_close_state = pending;
 
 #ifdef USE_TLS
   bool any_tls = false;
 #endif
-  const unsigned int nloaded = GL(dl_ns)[ns]._ns_nloaded;
+  const unsigned int nloaded = ns->_ns_nloaded;
   char used[nloaded];
   char done[nloaded];
   struct link_map *maps[nloaded];
@@ -141,7 +149,7 @@ _dl_close_worker (struct link_map *map)
   /* Run over the list and assign indexes to the link maps and enter
      them into the MAPS array.  */
   int idx = 0;
-  for (struct link_map *l = GL(dl_ns)[ns]._ns_loaded; l != NULL; l = l->l_next)
+  for (struct link_map *l = ns->_ns_loaded; l != NULL; l = l->l_next)
     {
       l->l_idx = idx;
       maps[idx] = l;
@@ -174,7 +182,7 @@ _dl_close_worker (struct link_map *map)
       done[done_index] = 1;
       used[done_index] = 1;
       /* Signal the object is still needed.  */
-      l->l_idx = -1;
+      l->l_idx = IDX_STILL_USED;
 
       /* Mark all dependencies as used.  */
       if (l->l_initfini != NULL)
@@ -182,7 +190,7 @@ _dl_close_worker (struct link_map *map)
          struct link_map **lp = &l->l_initfini[1];
          while (*lp != NULL)
            {
-             if ((*lp)->l_idx != -1)
+             if ((*lp)->l_idx != IDX_STILL_USED)
                {
                  assert ((*lp)->l_idx >= 0 && (*lp)->l_idx < nloaded);
 
@@ -203,7 +211,7 @@ _dl_close_worker (struct link_map *map)
          {
            struct link_map *jmap = l->l_reldeps[j];
 
-           if (jmap->l_idx != -1)
+           if (jmap->l_idx != IDX_STILL_USED)
              {
                assert (jmap->l_idx >= 0 && jmap->l_idx < nloaded);
 
@@ -218,20 +226,21 @@ _dl_close_worker (struct link_map *map)
     }
 
   /* Sort the entries.  */
-  _dl_sort_fini (GL(dl_ns)[ns]._ns_loaded, maps, nloaded, used, ns);
+  _dl_sort_fini (ns->_ns_loaded, maps, nloaded, used, nsid);
 
   /* Call all termination functions at once.  */
 #ifdef SHARED
-  bool do_audit = GLRO(dl_naudit) > 0 && !GL(dl_ns)[ns]._ns_loaded->l_auditing;
+  bool do_audit = GLRO(dl_naudit) > 0 && !ns->_ns_loaded->l_auditing;
 #endif
   bool unload_any = false;
+  unsigned int unload_global = 0;
   unsigned int first_loaded = ~0;
   for (unsigned int i = 0; i < nloaded; ++i)
     {
       struct link_map *imap = maps[i];
 
       /* All elements must be in the same namespace.  */
-      assert (imap->l_ns == ns);
+      assert (imap->l_ns == nsid);
 
       if (!used[i])
        {
@@ -246,7 +255,7 @@ _dl_close_worker (struct link_map *map)
              if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS,
                                    0))
                _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n",
-                                 imap->l_name, ns);
+                                 imap->l_name, nsid);
 
              if (imap->l_info[DT_FINI_ARRAY] != NULL)
                {
@@ -289,6 +298,9 @@ _dl_close_worker (struct link_map *map)
          /* We indeed have an object to remove.  */
          unload_any = true;
 
+         if (imap->l_global)
+           ++unload_global;
+
          /* Remember where the first dynamically loaded object is.  */
          if (i < first_loaded)
            first_loaded = i;
@@ -296,8 +308,9 @@ _dl_close_worker (struct link_map *map)
       /* Else used[i].  */
       else if (imap->l_type == lt_loaded)
        {
-         if (imap->l_searchlist.r_list == NULL
-             && imap->l_initfini != NULL)
+         struct r_scope_elem *new_list = NULL;
+
+         if (imap->l_searchlist.r_list == NULL && imap->l_initfini != NULL)
            {
              /* The object is still used.  But one of the objects we are
                 unloading right now is responsible for loading it.  If
@@ -314,44 +327,108 @@ _dl_close_worker (struct link_map *map)
              imap->l_searchlist.r_list = &imap->l_initfini[cnt + 1];
              imap->l_searchlist.r_nlist = cnt;
 
-             for (cnt = 0; imap->l_scope[cnt] != NULL; ++cnt)
-               /* This relies on l_scope[] entries being always set either
-                  to its own l_symbolic_searchlist address, or some map's
-                  l_searchlist address.  */
-               if (imap->l_scope[cnt] != &imap->l_symbolic_searchlist)
-                 {
-                   struct link_map *tmap;
-
-                   tmap = (struct link_map *) ((char *) imap->l_scope[cnt]
-                                               - offsetof (struct link_map,
-                                                           l_searchlist));
-                   assert (tmap->l_ns == ns);
-                   if (tmap->l_idx != -1)
-                     {
-                       imap->l_scope[cnt] = &imap->l_searchlist;
-                       break;
-                     }
-                 }
+             new_list = &imap->l_searchlist;
            }
-         else
+
+         /* Count the number of scopes which remain after the unload.
+            When we add the local search list count it.  Always add
+            one for the terminating NULL pointer.  */
+         size_t remain = (new_list != NULL) + 1;
+         bool removed_any = false;
+         for (size_t cnt = 0; imap->l_scope[cnt] != NULL; ++cnt)
+           /* This relies on l_scope[] entries being always set either
+              to its own l_symbolic_searchlist address, or some map's
+              l_searchlist address.  */
+           if (imap->l_scope[cnt] != &imap->l_symbolic_searchlist)
+             {
+               struct link_map *tmap = (struct link_map *)
+                 ((char *) imap->l_scope[cnt]
+                  - offsetof (struct link_map, l_searchlist));
+               assert (tmap->l_ns == nsid);
+               if (tmap->l_idx == IDX_STILL_USED)
+                 ++remain;
+               else
+                 removed_any = true;
+             }
+           else
+             ++remain;
+
+         if (removed_any)
            {
-             unsigned int cnt = 0;
-             while (imap->l_scope[cnt] != NULL)
+             /* Always allocate a new array for the scope.  This is
+                necessary since we must be able to determine the last
+                user of the current array.  If possible use the link map's
+                memory.  */
+             size_t new_size;
+             struct r_scope_elem **newp;
+
+#define SCOPE_ELEMS(imap) \
+  (sizeof (imap->l_scope_mem) / sizeof (imap->l_scope_mem[0]))
+
+             if (imap->l_scope != imap->l_scope_mem
+                 && remain < SCOPE_ELEMS (imap))
+               {
+                 new_size = SCOPE_ELEMS (imap);
+                 newp = imap->l_scope_mem;
+               }
+             else
                {
-                 if (imap->l_scope[cnt] == &map->l_searchlist)
+                 new_size = imap->l_scope_max;
+                 newp = (struct r_scope_elem **)
+                   malloc (new_size * sizeof (struct r_scope_elem *));
+                 if (newp == NULL)
+                   _dl_signal_error (ENOMEM, "dlclose", NULL,
+                                     N_("cannot create scope list"));
+               }
+
+             /* Copy over the remaining scope elements.  */
+             remain = 0;
+             for (size_t cnt = 0; imap->l_scope[cnt] != NULL; ++cnt)
+               {
+                 if (imap->l_scope[cnt] != &imap->l_symbolic_searchlist)
                    {
-                     while ((imap->l_scope[cnt] = imap->l_scope[cnt + 1])
-                            != NULL)
-                       ++cnt;
-                     break;
+                     struct link_map *tmap = (struct link_map *)
+                       ((char *) imap->l_scope[cnt]
+                        - offsetof (struct link_map, l_searchlist));
+                     if (tmap->l_idx != IDX_STILL_USED)
+                       {
+                         /* Remove the scope.  Or replace with own map's
+                            scope.  */
+                         if (new_list != NULL)
+                           {
+                             newp[remain++] = new_list;
+                             new_list = NULL;
+                           }
+                         continue;
+                       }
                    }
-                 ++cnt;
+
+                 newp[remain++] = imap->l_scope[cnt];
+               }
+             newp[remain] = NULL;
+
+             struct r_scope_elem **old = imap->l_scope;
+
+             if (RTLD_SINGLE_THREAD_P)
+               imap->l_scope = newp;
+             else
+               {
+                 __rtld_mrlock_change (imap->l_scope_lock);
+                 imap->l_scope = newp;
+                 __rtld_mrlock_done (imap->l_scope_lock);
                }
+
+             /* No user anymore, we can free it now.  */
+             if (old != imap->l_scope_mem)
+               free (old);
+
+             imap->l_scope_max = new_size;
            }
 
          /* The loader is gone, so mark the object as not having one.
-            Note: l_idx != -1 -> object will be removed.  */
-         if (imap->l_loader != NULL && imap->l_loader->l_idx != -1)
+            Note: l_idx != IDX_STILL_USED -> object will be removed.  */
+         if (imap->l_loader != NULL
+             && imap->l_loader->l_idx != IDX_STILL_USED)
            imap->l_loader = NULL;
 
          /* Remember where the first dynamically loaded object is.  */
@@ -368,7 +445,7 @@ _dl_close_worker (struct link_map *map)
   /* Auditing checkpoint: we will start deleting objects.  */
   if (__builtin_expect (do_audit, 0))
     {
-      struct link_map *head = GL(dl_ns)[ns]._ns_loaded;
+      struct link_map *head = ns->_ns_loaded;
       struct audit_ifaces *afct = GLRO(dl_audit);
       /* Do not call the functions for any auditing object.  */
       if (head->l_auditing == 0)
@@ -385,10 +462,38 @@ _dl_close_worker (struct link_map *map)
 #endif
 
   /* Notify the debugger we are about to remove some loaded objects.  */
-  struct r_debug *r = _dl_debug_initialize (0, ns);
+  struct r_debug *r = _dl_debug_initialize (0, nsid);
   r->r_state = RT_DELETE;
   _dl_debug_state ();
 
+  if (unload_global)
+    {
+      /* Some objects are in the global scope list.  Remove them.  */
+      struct r_scope_elem *ns_msl = ns->_ns_main_searchlist;
+      unsigned int i;
+      unsigned int j = 0;
+      unsigned int cnt = ns_msl->r_nlist;
+
+      while (cnt > 0 && ns_msl->r_list[cnt - 1]->l_removed)
+       --cnt;
+
+      if (cnt + unload_global == ns_msl->r_nlist)
+       /* Speed up removing most recently added objects.  */
+       j = cnt;
+      else
+       for (i = 0; i < cnt; i++)
+         if (ns_msl->r_list[i]->l_removed == 0)
+           {
+             if (i != j)
+               ns_msl->r_list[j] = ns_msl->r_list[i];
+             j++;
+           }
+      ns_msl->r_nlist = j;
+
+      if (!RTLD_SINGLE_THREAD_P)
+       THREAD_GSCOPE_WAIT ();
+    }
+
 #ifdef USE_TLS
   size_t tls_free_start;
   size_t tls_free_end;
@@ -406,23 +511,6 @@ _dl_close_worker (struct link_map *map)
 
          /* That was the last reference, and this was a dlopen-loaded
             object.  We can unmap it.  */
-         if (__builtin_expect (imap->l_global, 0))
-           {
-             /* This object is in the global scope list.  Remove it.  */
-             unsigned int cnt = GL(dl_ns)[ns]._ns_main_searchlist->r_nlist;
-
-             do
-               --cnt;
-             while (GL(dl_ns)[ns]._ns_main_searchlist->r_list[cnt] != imap);
-
-             /* The object was already correctly registered.  */
-             while (++cnt
-                    < GL(dl_ns)[ns]._ns_main_searchlist->r_nlist)
-               GL(dl_ns)[ns]._ns_main_searchlist->r_list[cnt - 1]
-                 = GL(dl_ns)[ns]._ns_main_searchlist->r_list[cnt];
-
-             --GL(dl_ns)[ns]._ns_main_searchlist->r_nlist;
-           }
 
 #ifdef USE_TLS
          /* Remove the object from the dtv slotinfo array if it uses TLS.  */
@@ -518,12 +606,12 @@ _dl_close_worker (struct link_map *map)
          else
            {
 #ifdef SHARED
-             assert (ns != LM_ID_BASE);
+             assert (nsid != LM_ID_BASE);
 #endif
-             GL(dl_ns)[ns]._ns_loaded = imap->l_next;
+             ns->_ns_loaded = imap->l_next;
            }
 
-         --GL(dl_ns)[ns]._ns_nloaded;
+         --ns->_ns_nloaded;
          if (imap->l_next != NULL)
            imap->l_next->l_prev = imap->l_prev;
 
@@ -587,7 +675,7 @@ _dl_close_worker (struct link_map *map)
   /* Auditing checkpoint: we have deleted all objects.  */
   if (__builtin_expect (do_audit, 0))
     {
-      struct link_map *head = GL(dl_ns)[ns]._ns_loaded;
+      struct link_map *head = ns->_ns_loaded;
       /* Do not call the functions for any auditing object.  */
       if (head->l_auditing == 0)
        {
@@ -673,22 +761,22 @@ free_slotinfo (struct dtv_slotinfo_list **elemp)
 
 libc_freeres_fn (free_mem)
 {
-  for (Lmid_t ns = 0; ns < DL_NNS; ++ns)
-    if (__builtin_expect (GL(dl_ns)[ns]._ns_global_scope_alloc, 0) != 0
-       && (GL(dl_ns)[ns]._ns_main_searchlist->r_nlist
+  for (Lmid_t nsid = 0; nsid < DL_NNS; ++nsid)
+    if (__builtin_expect (GL(dl_ns)[nsid]._ns_global_scope_alloc, 0) != 0
+       && (GL(dl_ns)[nsid]._ns_main_searchlist->r_nlist
            // XXX Check whether we need NS-specific initial_searchlist
            == GLRO(dl_initial_searchlist).r_nlist))
       {
        /* All object dynamically loaded by the program are unloaded.  Free
           the memory allocated for the global scope variable.  */
-       struct link_map **old = GL(dl_ns)[ns]._ns_main_searchlist->r_list;
+       struct link_map **old = GL(dl_ns)[nsid]._ns_main_searchlist->r_list;
 
        /* Put the old map in.  */
-       GL(dl_ns)[ns]._ns_main_searchlist->r_list
+       GL(dl_ns)[nsid]._ns_main_searchlist->r_list
          // XXX Check whether we need NS-specific initial_searchlist
          = GLRO(dl_initial_searchlist).r_list;
        /* Signal that the original map is used.  */
-       GL(dl_ns)[ns]._ns_global_scope_alloc = 0;
+       GL(dl_ns)[nsid]._ns_global_scope_alloc = 0;
 
        /* Now free the old map.  */
        free (old);
index 7cfcc620a7a7a693ca3f568c1232c55f67da477b..6108d0ea8821739a98990115f93e4146359158fb 100644 (file)
@@ -25,6 +25,7 @@
 #include <ldsodefs.h>
 #include <dl-hash.h>
 #include <dl-machine.h>
+#include <sysdep-cancel.h>
 #include <bits/libc-lock.h>
 #include <tls.h>
 
@@ -85,7 +86,7 @@ dl_new_hash (const char *s)
 /* Add extra dependency on MAP to UNDEF_MAP.  */
 static int
 internal_function
-add_dependency (struct link_map *undef_map, struct link_map *map)
+add_dependency (struct link_map *undef_map, struct link_map *map, int flags)
 {
   struct link_map **list;
   struct link_map *runp;
@@ -98,8 +99,18 @@ add_dependency (struct link_map *undef_map, struct link_map *map)
   if (undef_map == map)
     return 0;
 
-  /* Make sure nobody can unload the object while we are at it.  */
-  __rtld_lock_lock_recursive (GL(dl_load_lock));
+  /* Make sure nobody can unload the object while we are at it.
+     If we hold a scope lock drop it now to avoid ABBA locking problems.  */
+  if ((flags & DL_LOOKUP_SCOPE_LOCK) != 0 && !RTLD_SINGLE_THREAD_P)
+    {
+      __rtld_mrlock_unlock (undef_map->l_scope_lock);
+
+      __rtld_lock_lock_recursive (GL(dl_load_lock));
+
+      __rtld_mrlock_lock (undef_map->l_scope_lock);
+    }
+  else
+    __rtld_lock_lock_recursive (GL(dl_load_lock));
 
   /* Avoid references to objects which cannot be unloaded anyway.  */
   if (map->l_type != lt_loaded
@@ -200,14 +211,17 @@ add_dependency (struct link_map *undef_map, struct link_map *map)
 static void
 internal_function
 _dl_debug_bindings (const char *undef_name, struct link_map *undef_map,
-                   const ElfW(Sym) **ref, struct r_scope_elem *symbol_scope[],
-                   struct sym_val *value,
+                   const ElfW(Sym) **ref, struct sym_val *value,
                    const struct r_found_version *version, int type_class,
                    int protected);
 
 
 /* Search loaded objects' symbol tables for a definition of the symbol
-   UNDEF_NAME, perhaps with a requested version for the symbol.  */
+   UNDEF_NAME, perhaps with a requested version for the symbol.
+
+   We must never have calls to the audit functions inside this function
+   or in any function which gets called.  If this would happen the audit
+   code might create a thread which can throw off all the scope locking.  */
 lookup_t
 internal_function
 _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
@@ -223,19 +237,16 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
 
   bump_num_relocations ();
 
-  /* No other flag than DL_LOOKUP_ADD_DEPENDENCY is allowed if we look
-     up a versioned symbol.  */
-  assert (version == NULL || flags == 0 || flags == DL_LOOKUP_ADD_DEPENDENCY);
+  /* No other flag than DL_LOOKUP_ADD_DEPENDENCY and DL_LOOKUP_SCOPE_LOCK
+     is allowed if we look up a versioned symbol.  */
+  assert (version == NULL || (flags & ~(DL_LOOKUP_ADD_DEPENDENCY
+                                       | DL_LOOKUP_SCOPE_LOCK)) == 0);
 
   size_t i = 0;
   if (__builtin_expect (skip_map != NULL, 0))
-    {
-      /* Search the relevant loaded objects for a definition.  */
-      while ((*scope)->r_list[i] != skip_map)
-       ++i;
-
-      assert (i < (*scope)->r_nlist);
-    }
+    /* Search the relevant loaded objects for a definition.  */
+    while ((*scope)->r_list[i] != skip_map)
+      ++i;
 
   /* Search the relevant loaded objects for a definition.  */
   for (size_t start = i; *scope != NULL; start = 0, ++scope)
@@ -335,19 +346,20 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
         runtime lookups.  */
       && (flags & DL_LOOKUP_ADD_DEPENDENCY) != 0
       /* Add UNDEF_MAP to the dependencies.  */
-      && add_dependency (undef_map, current_value.m) < 0)
+      && add_dependency (undef_map, current_value.m, flags) < 0)
       /* Something went wrong.  Perhaps the object we tried to reference
         was just removed.  Try finding another definition.  */
       return _dl_lookup_symbol_x (undef_name, undef_map, ref,
-                                 symbol_scope, version, type_class,
-                                 flags, skip_map);
+                                 (flags & DL_LOOKUP_SCOPE_LOCK) == 0
+                                 ? symbol_scope : undef_map->l_scope, version,
+                                 type_class, flags, skip_map);
 
   /* The object is used.  */
   current_value.m->l_used = 1;
 
   if (__builtin_expect (GLRO(dl_debug_mask)
                        & (DL_DEBUG_BINDINGS|DL_DEBUG_PRELINK), 0))
-    _dl_debug_bindings (undef_name, undef_map, ref, symbol_scope,
+    _dl_debug_bindings (undef_name, undef_map, ref,
                        &current_value, version, type_class, protected);
 
   *ref = current_value.s;
@@ -404,8 +416,7 @@ _dl_setup_hash (struct link_map *map)
 static void
 internal_function
 _dl_debug_bindings (const char *undef_name, struct link_map *undef_map,
-                   const ElfW(Sym) **ref, struct r_scope_elem *symbol_scope[],
-                   struct sym_val *value,
+                   const ElfW(Sym) **ref, struct sym_val *value,
                    const struct r_found_version *version, int type_class,
                    int protected)
 {
index 86f7a8e4d9355d3427a733764e85558918bbe29c..266909c5fec9930c3a1ab5b86bff5272030abfe9 100644 (file)
@@ -85,6 +85,11 @@ _dl_new_object (char *realname, const char *libname, int type,
   new->l_scope = new->l_scope_mem;
   new->l_scope_max = sizeof (new->l_scope_mem) / sizeof (new->l_scope_mem[0]);
 
+  /* No need to initialize the scope lock if the initializer is zero.  */
+#if _RTLD_MRLOCK_INITIALIZER != 0
+  __rtld_mrlock_initialize (new->l_scope_lock);
+#endif
+
   /* Counter for the scopes we have to handle.  */
   idx = 0;
 
index bb80e77095bc3dbca6474fc4e662c33156ec1607..d0feb38041ee54997ca533065ad7dd40356550e3 100644 (file)
@@ -31,6 +31,8 @@
 #include <ldsodefs.h>
 #include <bp-sym.h>
 #include <caller.h>
+#include <sysdep-cancel.h>
+#include <tls.h>
 
 #include <dl-dst.h>
 
@@ -96,17 +98,17 @@ add_to_global (struct link_map *new)
      in an realloc() call.  Therefore we allocate a completely new
      array the first time we have to add something to the locale scope.  */
 
-  if (GL(dl_ns)[new->l_ns]._ns_global_scope_alloc == 0)
+  struct link_namespaces *ns = &GL(dl_ns)[new->l_ns];
+  if (ns->_ns_global_scope_alloc == 0)
     {
       /* This is the first dynamic object given global scope.  */
-      GL(dl_ns)[new->l_ns]._ns_global_scope_alloc
-       = GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist + to_add + 8;
+      ns->_ns_global_scope_alloc
+       = ns->_ns_main_searchlist->r_nlist + to_add + 8;
       new_global = (struct link_map **)
-       malloc (GL(dl_ns)[new->l_ns]._ns_global_scope_alloc
-               * sizeof (struct link_map *));
+       malloc (ns->_ns_global_scope_alloc * sizeof (struct link_map *));
       if (new_global == NULL)
        {
-         GL(dl_ns)[new->l_ns]._ns_global_scope_alloc = 0;
+         ns->_ns_global_scope_alloc = 0;
        nomem:
          _dl_signal_error (ENOMEM, new->l_libname->name, NULL,
                            N_("cannot extend global scope"));
@@ -114,29 +116,39 @@ add_to_global (struct link_map *new)
        }
 
       /* Copy over the old entries.  */
-      GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list
-       = memcpy (new_global,
-                 GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list,
-                 (GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist
+      ns->_ns_main_searchlist->r_list
+       = memcpy (new_global, ns->_ns_main_searchlist->r_list,
+                 (ns->_ns_main_searchlist->r_nlist
                   * sizeof (struct link_map *)));
     }
-  else if (GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist + to_add
-          > GL(dl_ns)[new->l_ns]._ns_global_scope_alloc)
+  else if (ns->_ns_main_searchlist->r_nlist + to_add
+          > ns->_ns_global_scope_alloc)
     {
       /* 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 (GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list,
-                ((GL(dl_ns)[new->l_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;
 
-      GL(dl_ns)[new->l_ns]._ns_global_scope_alloc += to_add + 8;
-      GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list = new_global;
+      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.  */
+  unsigned int new_nlist = ns->_ns_main_searchlist->r_nlist;
   for (cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt)
     {
       struct link_map *map = new->l_searchlist.r_list[cnt];
@@ -144,11 +156,11 @@ add_to_global (struct link_map *new)
       if (map->l_global == 0)
        {
          map->l_global = 1;
-         GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list[GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist]
-           = map;
-         ++GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist;
+         ns->_ns_main_searchlist->r_list[new_nlist++] = map;
        }
     }
+  atomic_write_barrier ();
+  ns->_ns_main_searchlist->r_nlist = new_nlist;
 
   return 0;
 }
@@ -380,6 +392,8 @@ dl_open_worker (void *a)
 
          while (*runp != NULL)
            {
+             if (*runp == &new->l_searchlist)
+               break;
              ++cnt;
              ++runp;
            }
@@ -392,35 +406,52 @@ dl_open_worker (void *a)
            {
              /* The 'r_scope' array is too small.  Allocate a new one
                 dynamically.  */
+             size_t new_size;
              struct r_scope_elem **newp;
-             size_t new_size = imap->l_scope_max * 2;
 
-             if (imap->l_scope == imap->l_scope_mem)
+#define SCOPE_ELEMS(imap) \
+  (sizeof (imap->l_scope_mem) / sizeof (imap->l_scope_mem[0]))
+
+             if (imap->l_scope != imap->l_scope_mem
+                 && imap->l_scope_max < SCOPE_ELEMS (imap))
+               {
+                 new_size = SCOPE_ELEMS (imap);
+                 newp = imap->l_scope_mem;
+               }
+             else
                {
+                 new_size = imap->l_scope_max * 2;
                  newp = (struct r_scope_elem **)
                    malloc (new_size * sizeof (struct r_scope_elem *));
                  if (newp == NULL)
                    _dl_signal_error (ENOMEM, "dlopen", NULL,
                                      N_("cannot create scope list"));
-                 imap->l_scope = memcpy (newp, imap->l_scope,
-                                         cnt * sizeof (imap->l_scope[0]));
                }
+
+             memcpy (newp, imap->l_scope, cnt * sizeof (imap->l_scope[0]));
+             struct r_scope_elem **old = imap->l_scope;
+
+             if (RTLD_SINGLE_THREAD_P)
+               imap->l_scope = newp;
              else
                {
-                 newp = (struct r_scope_elem **)
-                   realloc (imap->l_scope,
-                            new_size * sizeof (struct r_scope_elem *));
-                 if (newp == NULL)
-                   _dl_signal_error (ENOMEM, "dlopen", NULL,
-                                     N_("cannot create scope list"));
+                 __rtld_mrlock_change (imap->l_scope_lock);
                  imap->l_scope = newp;
+                 __rtld_mrlock_done (imap->l_scope_lock);
                }
 
+             if (old != imap->l_scope_mem)
+               free (old);
+
              imap->l_scope_max = new_size;
            }
 
-         imap->l_scope[cnt++] = &new->l_searchlist;
-         imap->l_scope[cnt] = NULL;
+         /* First terminate the extended list.  Otherwise a thread
+            might use the new last element and then use the garbage
+            at offset IDX+1.  */
+         imap->l_scope[cnt + 1] = NULL;
+         atomic_write_barrier ();
+         imap->l_scope[cnt] = &new->l_searchlist;
        }
 #if USE_TLS
       /* Only add TLS memory if this object is loaded now and
index f92cbe26bd25c9d9086b0c5dab3c3be1eb8f4e2b..72f7c067cb5c49241b0f4d931d17a97899eb68b9 100644 (file)
 #include <unistd.h>
 #include <sys/param.h>
 #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
@@ -92,16 +95,37 @@ _dl_fixup (
            version = NULL;
        }
 
-      result = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym,
-                                   l->l_scope, version, ELF_RTYPE_CLASS_PLT,
-                                   DL_LOOKUP_ADD_DEPENDENCY, NULL);
+      /* We need to keep the scope around so do some locking.  This is
+        not necessary for objects which cannot be unloaded or when
+        we are not using any threads (yet).  */
+      int flags = DL_LOOKUP_ADD_DEPENDENCY;
+      if (!RTLD_SINGLE_THREAD_P)
+       {
+         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,
+                                   version, ELF_RTYPE_CLASS_PLT, flags, NULL);
+
+      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.  */
       value = DL_FIXUP_MAKE_VALUE (result,
-                                  sym ? LOOKUP_VALUE_ADDRESS (result)
-                                        + sym->st_value : 0);
+                                  sym ? (LOOKUP_VALUE_ADDRESS (result)
+                                         + sym->st_value) : 0);
     }
   else
     {
@@ -174,10 +198,31 @@ _dl_profile_fixup (
                version = NULL;
            }
 
-         result = _dl_lookup_symbol_x (strtab + refsym->st_name, l, &defsym,
-                                       l->l_scope, version,
-                                       ELF_RTYPE_CLASS_PLT,
-                                       DL_LOOKUP_ADD_DEPENDENCY, NULL);
+         /* We need to keep the scope around so do some locking.  This is
+            not necessary for objects which cannot be unloaded or when
+            we are not using any threads (yet).  */
+         int flags = DL_LOOKUP_ADD_DEPENDENCY;
+         if (!RTLD_SINGLE_THREAD_P)
+           {
+             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,
+                                       &defsym, l->l_scope, version,
+                                       ELF_RTYPE_CLASS_PLT, flags, NULL);
+
+         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
index 3b1b35d8afbe6964eaca8377fa03bcb639f92782..8118cfbc945065bcad5ff3590e5e66890c8159e9 100644 (file)
@@ -134,6 +134,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 d2b0ec0dab94650a31c9298c52267ba3401d4a2f..20235ae2e6ae46b44bcb6d9ffba40beaebf5d124 100644 (file)
@@ -17,6 +17,7 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
+#include <assert.h>
 #include <stddef.h>
 #include <setjmp.h>
 #include <libintl.h>
@@ -24,6 +25,7 @@
 #include <dlfcn.h>
 #include <ldsodefs.h>
 #include <dl-hash.h>
+#include <sysdep-cancel.h>
 #ifdef USE_TLS
 # include <dl-tls.h>
 #endif
@@ -58,6 +60,29 @@ _dl_tls_symaddr (struct link_map *map, const ElfW(Sym) *ref)
 #endif
 
 
+struct call_dl_lookup_args
+{
+  /* Arguments to do_dlsym.  */
+  struct link_map *map;
+  const char *name;
+  struct r_found_version *vers;
+  int flags;
+
+  /* Return values of do_dlsym.  */
+  lookup_t loadbase;
+  const ElfW(Sym) **refp;
+};
+
+static void
+call_dl_lookup (void *ptr)
+{
+  struct call_dl_lookup_args *args = (struct call_dl_lookup_args *) ptr;
+  args->map = GLRO(dl_lookup_symbol_x) (args->name, args->map, args->refp,
+                                       args->map->l_scope, args->vers, 0,
+                                       args->flags, NULL);
+}
+
+
 static void *
 internal_function
 do_sym (void *handle, const char *name, void *who,
@@ -84,10 +109,51 @@ do_sym (void *handle, const char *name, void *who,
        }
 
   if (handle == RTLD_DEFAULT)
-    /* Search the global scope.  */
-    result = GLRO(dl_lookup_symbol_x) (name, match, &ref, match->l_scope,
-                                      vers, 0, flags|DL_LOOKUP_ADD_DEPENDENCY,
-                                      NULL);
+    {
+      /* Search the global scope.  We have the simple case where
+        we look up in the scope of an object which was part of
+        the initial binary.  And then the more complex part
+        where the object is dynamically loaded and the scope
+        array can change.  */
+      if (match->l_type != lt_loaded || RTLD_SINGLE_THREAD_P)
+       result = GLRO(dl_lookup_symbol_x) (name, match, &ref,
+                                          match->l_scope, vers, 0,
+                                          flags | DL_LOOKUP_ADD_DEPENDENCY,
+                                          NULL);
+      else
+       {
+         __rtld_mrlock_lock (match->l_scope_lock);
+
+         struct call_dl_lookup_args args;
+         args.name = name;
+         args.map = match;
+         args.vers = vers;
+         args.flags = flags | DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_SCOPE_LOCK;
+         args.refp = &ref;
+
+         const char *objname;
+         const char *errstring = NULL;
+         bool malloced;
+         int err = GLRO(dl_catch_error) (&objname, &errstring, &malloced,
+                                         call_dl_lookup, &args);
+
+         __rtld_mrlock_unlock (match->l_scope_lock);
+
+         if (__builtin_expect (errstring != NULL, 0))
+           {
+             /* The lookup was unsuccessful.  Rethrow the error.  */
+             char *errstring_dup = strdupa (errstring);
+             char *objname_dup = strdupa (objname);
+             if (malloced)
+               free ((char *) errstring);
+
+             GLRO(dl_signal_error) (err, objname_dup, NULL, errstring_dup);
+             /* NOTREACHED */
+           }
+
+         result = args.map;
+       }
+    }
   else if (handle == RTLD_NEXT)
     {
       if (__builtin_expect (match == GL(dl_ns)[LM_ID_BASE]._ns_loaded, 0))
index 2585d8300547629876cc2b62c2c886bc17c57819..b68cc02889ee356445343327ebcc1a33f1644db5 100644 (file)
@@ -29,8 +29,13 @@ do_lookup_x (const char *undef_name, uint_fast32_t new_hash,
             const struct r_found_version *const version, int flags,
             struct link_map *skip, int type_class)
 {
-  struct link_map **list = scope->r_list;
   size_t n = scope->r_nlist;
+  /* Make sure we read the value before proceeding.  Otherwise we
+     might use r_list pointing to the initial scope and r_nlist being
+     the value after a resize.  That is the only path in dl-open.c not
+     protected by GSCOPE.  A read barrier here might be to expensive.  */
+  __asm volatile ("" : "+r" (n), "+m" (scope->r_list));
+  struct link_map **list = scope->r_list;
 
   do
     {
index 7746377f37129bb441b2fde840a7520022e5a3b4..584d216f708a0b24cf333286b43a5cbf71375108 100644 (file)
@@ -2143,7 +2143,6 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
 
   /* Now set up the variable which helps the assembler startup code.  */
   GL(dl_ns)[LM_ID_BASE]._ns_main_searchlist = &main_map->l_searchlist;
-  GL(dl_ns)[LM_ID_BASE]._ns_global_scope[0] = &main_map->l_searchlist;
 
   /* Save the information about the original global scope list since
      we need it in the memory handling later.  */
index 0d6b66100e46b5c6ed9dbf834830b7c02d05ae02..1bc4917c38273a0861fe323820f509340846078f 100644 (file)
@@ -42,7 +42,9 @@ extern unsigned int la_objopen (struct link_map *__map, Lmid_t __lmid,
 #include <stddef.h>
 #include <bits/linkmap.h>
 #include <dl-lookupcfg.h>
-#include <tls.h>               /* Defines USE_TLS.  */
+#include <tls.h>
+#include <bits/libc-lock.h>
+#include <rtld-lowlevel.h>
 
 
 /* Some internal data structures of the dynamic linker used in the
@@ -218,6 +220,8 @@ struct link_map
     /* This is an array defining the lookup scope for this link map.
        There are initially at most three different scope lists.  */
     struct r_scope_elem **l_scope;
+    /* We need to protect using the SCOPEREC.  */
+    __rtld_mrlock_define (, l_scope_lock)
 
     /* A similar array, this time only with the local scope.  This is
        used occasionally.  */
index fbc66c6b732ba6b6c14f39fd7e32f69dd2f61d79..97036aa2f83f99dc8108d7b1c18d18b5b0e2cacb 100644 (file)
@@ -1,3 +1,142 @@
+2007-05-28  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/i386/tls.h (THREAD_GSCOPE_RESET_FLAG): Use explicit
+       insn suffix.
+       (THREAD_GSCOPE_GET_FLAG): Remove.
+       * sysdeps/x86_64/tls.h (THREAD_GSCOPE_GET_FLAG): Remove.
+       * allocatestack.c (__wait_lookup_done): Revert 2007-05-24
+       changes.
+       * sysdeps/powerpc/tls.h (tcbhead_t): Remove gscope_flag.
+       (THREAD_GSCOPE_GET_FLAG): Remove.
+       (THREAD_GSCOPE_RESET_FLAG): Use THREAD_SELF->header.gscope_flag
+       instead of THREAD_GSCOPE_GET_FLAG.
+       (THREAD_GSCOPE_SET_FLAG): Likewise.  Add atomic_write_barrier after
+       it.
+       * sysdeps/s390/tls.h (THREAD_GSCOPE_FLAG_UNUSED,
+       THREAD_GSCOPE_FLAG_USED, THREAD_GSCOPE_FLAG_WAIT,
+       THREAD_GSCOPE_RESET_FLAG, THREAD_GSCOPE_SET_FLAG,
+       THREAD_GSCOPE_WAIT): Define.
+       * sysdeps/sparc/tls.h (THREAD_GSCOPE_FLAG_UNUSED,
+       THREAD_GSCOPE_FLAG_USED, THREAD_GSCOPE_FLAG_WAIT,
+       THREAD_GSCOPE_RESET_FLAG, THREAD_GSCOPE_SET_FLAG,
+       THREAD_GSCOPE_WAIT): Define.
+       * sysdeps/sh/tls.h (THREAD_GSCOPE_FLAG_UNUSED,
+       THREAD_GSCOPE_FLAG_USED, THREAD_GSCOPE_FLAG_WAIT,
+       THREAD_GSCOPE_RESET_FLAG, THREAD_GSCOPE_SET_FLAG,
+       THREAD_GSCOPE_WAIT): Define.
+       * sysdeps/ia64/tls.h (THREAD_GSCOPE_FLAG_UNUSED,
+       THREAD_GSCOPE_FLAG_USED, THREAD_GSCOPE_FLAG_WAIT,
+       THREAD_GSCOPE_RESET_FLAG, THREAD_GSCOPE_SET_FLAG,
+       THREAD_GSCOPE_WAIT): Define.
+
+2007-05-24  Richard Henderson  <rth@redhat.com>
+
+       * descr.h (struct pthread): Add header.gscope_flag.
+       * sysdeps/alpha/tls.h (THREAD_GSCOPE_FLAG_UNUSED,
+       THREAD_GSCOPE_FLAG_USED, THREAD_GSCOPE_FLAG_WAIT,
+       THREAD_GSCOPE_RESET_FLAG, THREAD_GSCOPE_SET_FLAG,
+       THREAD_GSCOPE_WAIT): Define.
+
+2007-05-26  Ulrich Drepper  <drepper@redhat.com>
+
+       * allocatestack.c: Revert last change.
+       * init.c: Likewise.
+       * sysdeps/i386/tls.h: Likewise.
+       * sysdeps/x86_64/tls.h: Likewise.
+
+2007-05-24  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/powerpc/tls.h (tcbhead_t): Add gscope_flag.
+       (THREAD_GSCOPE_FLAG_UNUSED, THREAD_GSCOPE_FLAG_USED,
+       THREAD_GSCOPE_FLAG_WAIT): Define.
+       (THREAD_GSCOPE_GET_FLAG, THREAD_GSCOPE_SET_FLAG,
+       THREAD_GSCOPE_RESET_FLAG, THREAD_GSCOPE_WAIT): Define.
+       * sysdeps/i386/tls.h (THREAD_GSCOPE_WAIT): Don't use
+       PTR_DEMANGLE.
+       (THREAD_GSCOPE_GET_FLAG): Define.
+       * sysdeps/x86_64/tls.h (THREAD_GSCOPE_GET_FLAG): Define.
+       * allocatestack.c (__wait_lookup_done): Use THREAD_GSCOPE_GET_FLAG
+       instead of ->header.gscope_flag directly.
+
+2007-05-21  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/pthread-functions.h (struct pthread_functions):
+       Remove ptr_wait_lookup_done again.
+       * init.c (pthread_functions): Don't add .ptr_wait_lookup_done here.
+       (__pthread_initialize_minimal_internal): Initialize
+       _dl_wait_lookup_done pointer in _rtld_global directly.
+       * sysdeps/unix/sysv/linux/libc_pthread_init.c (__libc_pthread_init):
+       Remove code to code _dl_wait_lookup_done.
+       * sysdeps/x86_64/tls.h (THREAD_GSCOPE_WAIT): The pointer is not
+       encrypted for now.
+
+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).
+
+2006-12-09  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/rtld-lowlevel.h
+       (__rtld_mrlock_initialize): Add missing closing parenthesis.
+
+2006-10-29  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h (RTLD_SINGLE_THREAD_P):
+       Define.
+       (SINGLE_THREAD_P): Define to 1 if IS_IN_rtld.
+       * sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h: Likewise.
+
+2006-10-27  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/rtld-lowlevel.h (__rtld_mrlock_lock,
+       __rtld_mrlock_change): Update oldval if atomic compare and exchange
+       failed.
+
+       * sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h (SINGLE_THREAD_P):
+       Define to THREAD_SELF->header.multiple_threads.
+       * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h (SINGLE_THREAD_P):
+       Likewise.
+       * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h (SINGLE_THREAD_P):
+       Likewise.
+       * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h
+       (SINGLE_THREAD_P): Likewise.
+       * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h
+       (SINGLE_THREAD_P): Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h
+       (SINGLE_THREAD_P): Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h
+       (SINGLE_THREAD_P): Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h (SINGLE_THREAD_P):
+       Likewise.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h
+       (SINGLE_THREAD_P): Likewise.
+       * sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h
+       (SINGLE_THREAD_P): Likewise.
+       * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h (SINGLE_THREAD_P):
+       Likewise.
+
+2006-10-09  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/rtld-lowlevel.h: New file..
+
 2007-05-25  Ulrich Drepper  <drepper@redhat.com>
 
        * Makefile (tests): Add tst-sem10.
index c05cd47dffdb63f38dae29b447118970082cc2de..6c456d9aa9382e8323d967e0cf48484afd4c44d8 100644 (file)
@@ -982,3 +982,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 321ce85085715b6d38b186642916d7e92f291de5..f462869285bbf38e493caaa36267633e29bd5002 100644 (file)
@@ -131,6 +131,7 @@ struct pthread
     struct
     {
       int multiple_threads;
+      int gscope_flag;
     } header;
 #endif
 
index 14441153b8e28de944013cdf7103304a7ce28bbf..edf133b011d3917ba1dea5af0c5d6b82717d1239 100644 (file)
@@ -386,6 +386,8 @@ __pthread_initialize_minimal_internal (void)
 
   GL(dl_init_static_tls) = &__pthread_init_static_tls;
 
+  GL(dl_wait_lookup_done) = &__wait_lookup_done;
+
   /* Register the fork generation counter with the libc.  */
 #ifndef TLS_MULTIPLE_THREADS_IN_TCB
   __libc_multiple_threads_ptr =
index f9634ab0ffac97210688164b7e6acab347d66c96..f560f72e4e5bfeed9482b06e8e905e50b55ea5fa 100644 (file)
@@ -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 20f780c5f53002235cb81aab8df542374207f4f2..fbcd97163a6acf86d791a2bdd758ae8f595e5d95 100644 (file)
@@ -124,6 +124,29 @@ typedef struct
 #define THREAD_SETMEM_NC(descr, member, idx, value) \
   descr->member[idx] = (value)
 
+/* Get and set the global scope generation counter in struct pthread.  */
+#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                                                                     \
+       = atomic_exchange_rel (&THREAD_SELF->header.gscope_flag,             \
+                              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() \
+  do                                                                        \
+    {                                                                       \
+      THREAD_SELF->header.gscope_flag = THREAD_GSCOPE_FLAG_USED;            \
+      atomic_write_barrier ();                                              \
+    }                                                                       \
+  while (0)
+#define THREAD_GSCOPE_WAIT() \
+  GL(dl_wait_lookup_done) ()
+
 #endif /* __ASSEMBLER__ */
 
 #endif /* tls.h */
index a870a848cf4deaf006d0ccdab67091978a627d73..933984fbfa588b073b0dc3778e83efbf3767186d 100644 (file)
@@ -51,6 +51,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
@@ -434,6 +435,26 @@ 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 ("xchgl %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)
+#define THREAD_GSCOPE_WAIT() \
+  GL(dl_wait_lookup_done) ()
+
 #endif /* __ASSEMBLER__ */
 
 #endif /* tls.h */
index 69101ad8c4c6941f91e590afea274dc3451a78aa..93e8137a7a09046d164cefcb7f879afda3b16728 100644 (file)
@@ -166,6 +166,29 @@ register struct pthread *__thread_self __asm__("r13");
   (((uintptr_t *) ((char *) (descr) + TLS_PRE_TCB_SIZE))[-2] \
    = THREAD_GET_POINTER_GUARD ())
 
+/* Get and set the global scope generation counter in struct pthread.  */
+#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                                                                     \
+       = atomic_exchange_rel (&THREAD_SELF->header.gscope_flag,             \
+                              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() \
+  do                                                                        \
+    {                                                                       \
+      THREAD_SELF->header.gscope_flag = THREAD_GSCOPE_FLAG_USED;            \
+      atomic_write_barrier ();                                              \
+    }                                                                       \
+  while (0)
+#define THREAD_GSCOPE_WAIT() \
+  GL(dl_wait_lookup_done) ()
+
 #endif /* __ASSEMBLER__ */
 
 #endif /* tls.h */
index 976a27136292ee7c2ac63ffbf7c7d849e80eca1a..e87e1dc1e2044945346e73c2c01929292b86eca1 100644 (file)
@@ -183,6 +183,29 @@ register void *__thread_register __asm__ ("r13");
    different value to mean unset l_tls_offset.  */
 # define NO_TLS_OFFSET         -1
 
+/* Get and set the global scope generation counter in struct pthread.  */
+#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                                                                     \
+       = atomic_exchange_rel (&THREAD_SELF->header.gscope_flag,             \
+                              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() \
+  do                                                                        \
+    {                                                                       \
+      THREAD_SELF->header.gscope_flag = THREAD_GSCOPE_FLAG_USED;            \
+      atomic_write_barrier ();                                              \
+    }                                                                       \
+  while (0)
+#define THREAD_GSCOPE_WAIT() \
+  GL(dl_wait_lookup_done) ()
+
 #endif /* __ASSEMBLER__ */
 
 #endif /* tls.h */
index 89ff095d522ed0cb59d455bebbe50e5b8e581227..b7fa569455f4c21ff654aea2e3b4b5cc735215ce 100644 (file)
@@ -50,6 +50,7 @@ typedef struct
   int multiple_threads;
   uintptr_t sysinfo;
   uintptr_t stack_guard;
+  int gscope_flag;
 } tcbhead_t;
 
 # ifndef __s390x__
@@ -171,6 +172,29 @@ typedef struct
 #define THREAD_SET_POINTER_GUARD(value)
 #define THREAD_COPY_POINTER_GUARD(descr)
 
+/* Get and set the global scope generation counter in struct pthread.  */
+#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                                                                     \
+       = atomic_exchange_rel (&THREAD_SELF->header.gscope_flag,             \
+                              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() \
+  do                                                                        \
+    {                                                                       \
+      THREAD_SELF->header.gscope_flag = THREAD_GSCOPE_FLAG_USED;            \
+      atomic_write_barrier ();                                              \
+    }                                                                       \
+  while (0)
+#define THREAD_GSCOPE_WAIT() \
+  GL(dl_wait_lookup_done) ()
+
 #endif /* __ASSEMBLER__ */
 
 #endif /* tls.h */
index 49d105518a38f3e2cc9059fd1a4bd5d9d1ccf65e..829ad00f128dfbc2bd95090ab41d3d23fe5477e6 100644 (file)
@@ -153,6 +153,29 @@ typedef struct
      __asm __volatile ("stc gbr,%0" : "=r" (__tcbp));                        \
      ((tcbhead_t *) (descr + 1))->pointer_guard        = __tcbp->pointer_guard;})
 
+/* Get and set the global scope generation counter in struct pthread.  */
+#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                                                                     \
+       = atomic_exchange_rel (&THREAD_SELF->header.gscope_flag,             \
+                              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() \
+  do                                                                        \
+    {                                                                       \
+      THREAD_SELF->header.gscope_flag = THREAD_GSCOPE_FLAG_USED;            \
+      atomic_write_barrier ();                                              \
+    }                                                                       \
+  while (0)
+#define THREAD_GSCOPE_WAIT() \
+  GL(dl_wait_lookup_done) ()
+
 #endif /* __ASSEMBLER__ */
 
 #endif /* tls.h */
index 127bbf695f4d1e0b1f2510fbe84d4fcad942ccef..7fead5a97c295441684f38f9c724eb5f1d5f9085 100644 (file)
@@ -144,6 +144,29 @@ register struct pthread *__thread_self __asm__("%g7");
 # define THREAD_COPY_POINTER_GUARD(descr) \
   ((descr)->header.pointer_guard = THREAD_GET_POINTER_GUARD ())
 
+/* Get and set the global scope generation counter in struct pthread.  */
+#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                                                                     \
+       = atomic_exchange_rel (&THREAD_SELF->header.gscope_flag,             \
+                              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() \
+  do                                                                        \
+    {                                                                       \
+      THREAD_SELF->header.gscope_flag = THREAD_GSCOPE_FLAG_USED;            \
+      atomic_write_barrier ();                                              \
+    }                                                                       \
+  while (0)
+#define THREAD_GSCOPE_WAIT() \
+  GL(dl_wait_lookup_done) ()
+
 #endif /* !ASSEMBLER */
 
 #endif /* tls.h */
index f3f7718e3ee31498e6fa09f79397072e4d300f01..ba9ee12281cbb9bd2c6571857906be0378bf7f64 100644 (file)
@@ -167,3 +167,9 @@ extern int __local_multiple_threads attribute_hidden;
 # define NO_CANCELLATION 1
 
 #endif
+
+#ifndef __ASSEMBLER__
+# define RTLD_SINGLE_THREAD_P \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+                                  header.multiple_threads) == 0, 1)
+#endif
index 147f5c8470de65be178147e0a5589b2c12813d19..114a0250367474db00c4360ad0ad46107f5f83b8 100644 (file)
 # define NO_CANCELLATION 1
 
 #endif
+
+#ifndef __ASSEMBLER__
+# define RTLD_SINGLE_THREAD_P \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+                                  header.multiple_threads) == 0, 1)
+#endif
index 63aaa96eb045dce1f5bfa02de2e0bb5752579f54..27f3a9fd6cb08a4f6faaaa352e075130b8845286 100644 (file)
@@ -220,3 +220,9 @@ __GC_##name:                                                                      \
 # define NO_CANCELLATION 1
 
 #endif
+
+#ifndef __ASSEMBLER__
+# define RTLD_SINGLE_THREAD_P \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+                                  header.multiple_threads) == 0, 1)
+#endif
index dcbc0d652023695dfd0202f134f6816dad89275d..3752abc870b78fa9cc42e2cca56e6bad0149d05d 100644 (file)
 # define NO_CANCELLATION 1
 
 #endif
+
+#ifndef __ASSEMBLER__
+# define RTLD_SINGLE_THREAD_P \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+                                  header.multiple_threads) == 0, 1)
+#endif
index 83eb444ecec42a1a8ba0a459881c9da24a05ffe4..707765ab58e7278c4da9b45665a88379c658c525 100644 (file)
 # define NO_CANCELLATION 1
 
 #endif
+
+#ifndef __ASSEMBLER__
+# define RTLD_SINGLE_THREAD_P \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+                                  header.multiple_threads) == 0, 1)
+#endif
diff --git a/nptl/sysdeps/unix/sysv/linux/rtld-lowlevel.h b/nptl/sysdeps/unix/sysv/linux/rtld-lowlevel.h
new file mode 100644 (file)
index 0000000..39db5a3
--- /dev/null
@@ -0,0 +1,153 @@
+/* Defintions for lowlevel handling in ld.so.
+   Copyright (C) 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
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _RTLD_LOWLEVEL_H
+#define  _RTLD_LOWLEVEL_H 1
+
+#include <atomic.h>
+#include <lowlevellock.h>
+
+
+/* Special multi-reader lock used in ld.so.  */
+#define __RTLD_MRLOCK_WRITER 1
+#define __RTLD_MRLOCK_RWAIT 2
+#define __RTLD_MRLOCK_WWAIT 4
+#define __RTLD_MRLOCK_RBITS \
+  ~(__RTLD_MRLOCK_WRITER | __RTLD_MRLOCK_RWAIT | __RTLD_MRLOCK_WWAIT)
+#define __RTLD_MRLOCK_INC 8
+#define __RTLD_MRLOCK_TRIES 5
+
+
+typedef int __rtld_mrlock_t;
+
+
+#define __rtld_mrlock_define(CLASS,NAME) \
+  CLASS __rtld_mrlock_t NAME;
+
+
+#define _RTLD_MRLOCK_INITIALIZER 0
+#define __rtld_mrlock_initialize(NAME) \
+  (void) ((NAME) = 0)
+
+
+#define __rtld_mrlock_lock(lock) \
+  do {                                                                       \
+    __label__ out;                                                           \
+    while (1)                                                                \
+      {                                                                              \
+       int oldval;                                                           \
+       for (int tries = 0; tries < __RTLD_MRLOCK_TRIES; ++tries)             \
+         {                                                                   \
+           oldval = lock;                                                    \
+           while (__builtin_expect ((oldval                                  \
+                                     & (__RTLD_MRLOCK_WRITER                 \
+                                        | __RTLD_MRLOCK_WWAIT))              \
+                                    == 0, 1))                                \
+             {                                                               \
+               int newval = ((oldval & __RTLD_MRLOCK_RBITS)                  \
+                             + __RTLD_MRLOCK_INC);                           \
+               int ret = atomic_compare_and_exchange_val_acq (&(lock),       \
+                                                              newval,        \
+                                                              oldval);       \
+               if (__builtin_expect (ret == oldval, 1))                      \
+                 goto out;                                                   \
+               oldval = ret;                                                 \
+             }                                                               \
+           atomic_delay ();                                                  \
+         }                                                                   \
+       if ((oldval & __RTLD_MRLOCK_RWAIT) == 0)                              \
+         {                                                                   \
+           atomic_or (&(lock), __RTLD_MRLOCK_RWAIT);                         \
+           oldval |= __RTLD_MRLOCK_RWAIT;                                    \
+         }                                                                   \
+       lll_futex_wait (lock, oldval);                                        \
+      }                                                                              \
+  out:;                                                                              \
+  } while (0)
+
+
+#define __rtld_mrlock_unlock(lock) \
+  do {                                                                       \
+    int oldval = atomic_exchange_and_add (&(lock), -__RTLD_MRLOCK_INC);              \
+    if (__builtin_expect ((oldval                                            \
+                          & (__RTLD_MRLOCK_RBITS | __RTLD_MRLOCK_WWAIT))     \
+                         == (__RTLD_MRLOCK_INC | __RTLD_MRLOCK_WWAIT), 0))   \
+      /* We have to wake all threads since there might be some queued        \
+        readers already.  */                                                 \
+      lll_futex_wake (&(lock), 0x7fffffff);                                  \
+  } while (0)
+
+
+/* There can only ever be one thread trying to get the exclusive lock.  */
+#define __rtld_mrlock_change(lock) \
+  do {                                                                       \
+    __label__ out;                                                           \
+    while (1)                                                                \
+      {                                                                              \
+       int oldval;                                                           \
+       for (int tries = 0; tries < __RTLD_MRLOCK_TRIES; ++tries)             \
+         {                                                                   \
+           oldval = lock;                                                    \
+           while (__builtin_expect ((oldval & __RTLD_MRLOCK_RBITS) == 0, 1)) \
+             {                                                               \
+               int newval = ((oldval & __RTLD_MRLOCK_RWAIT)                  \
+                             + __RTLD_MRLOCK_WRITER);                        \
+               int ret = atomic_compare_and_exchange_val_acq (&(lock),       \
+                                                              newval,        \
+                                                              oldval);       \
+               if (__builtin_expect (ret == oldval, 1))                      \
+                 goto out;                                                   \
+               oldval = ret;                                                 \
+             }                                                               \
+           atomic_delay ();                                                  \
+         }                                                                   \
+       atomic_or (&(lock), __RTLD_MRLOCK_WWAIT);                             \
+       oldval |= __RTLD_MRLOCK_WWAIT;                                        \
+       lll_futex_wait (lock, oldval);                                        \
+      }                                                                              \
+  out:;                                                                              \
+  } while (0)
+
+
+#define __rtld_mrlock_done(lock) \
+  do {                          \
+    int oldval = atomic_exchange_and_add (&(lock), -__RTLD_MRLOCK_WRITER);    \
+    if (__builtin_expect ((oldval & __RTLD_MRLOCK_RWAIT) != 0, 0))           \
+      lll_futex_wake (&(lock), 0x7fffffff);                                  \
+  } while (0)
+
+
+/* Function to wait for variable become zero.  Used in ld.so for
+   reference counters.  */
+#define __rtld_waitzero(word) \
+  do {                                                                       \
+    while (1)                                                                \
+      {                                                                              \
+       int val = word;                                                       \
+       if (val == 0)                                                         \
+         break;                                                              \
+       lll_futex_wait (&(word), val);                                        \
+      }                                                                              \
+  } while (0)
+
+
+#define __rtld_notify(word) \
+  lll_futex_wake (&(word), 1)
+
+#endif
index 09dac2c90b2df0785c32d5b5bdd553a71885d5d0..c63266552bf697ac6f410207be5509612197ea2e 100644 (file)
@@ -113,3 +113,9 @@ L(pseudo_end):
 # define NO_CANCELLATION 1
 
 #endif
+
+#ifndef __ASSEMBLER__
+# define RTLD_SINGLE_THREAD_P \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+                                  header.multiple_threads) == 0, 1)
+#endif
index f8eb6a9ebcdab39d0d1fc47f5af1888b3963c79e..7c32549b5e62905c68e308153cab839bf15a1e1e 100644 (file)
@@ -126,3 +126,9 @@ extern int __local_multiple_threads attribute_hidden;
 # define NO_CANCELLATION 1
 
 #endif
+
+#ifndef __ASSEMBLER__
+# define RTLD_SINGLE_THREAD_P \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+                                  header.multiple_threads) == 0, 1)
+#endif
index 9a967eaf5372cf7e0b894f950cc227170afe4b1a..e4509a7264bb7dab17b28147a80a5ecfdb912e09 100644 (file)
 # define NO_CANCELLATION 1
 
 #endif
+
+#ifndef __ASSEMBLER__
+# define RTLD_SINGLE_THREAD_P \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+                                  header.multiple_threads) == 0, 1)
+#endif
index 75a4eb94698b2e3ca7877ec10e9005800c0ec9f9..15d92790c0abf765945f3838d6f3e05001377a48 100644 (file)
@@ -104,3 +104,9 @@ __##syscall_name##_nocancel:                        \
 # define NO_CANCELLATION 1
 
 #endif
+
+#ifndef __ASSEMBLER__
+# define RTLD_SINGLE_THREAD_P \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+                                  header.multiple_threads) == 0, 1)
+#endif
index dd263a597cf9ea5a690c7546359b0c09b1efbbd0..2c76d01715594797721681999d482a5337d79737 100644 (file)
@@ -102,3 +102,9 @@ __##syscall_name##_nocancel:                        \
 # define NO_CANCELLATION 1
 
 #endif
+
+#ifndef __ASSEMBLER__
+# define RTLD_SINGLE_THREAD_P \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+                                  header.multiple_threads) == 0, 1)
+#endif
index 97debaba99b20890c0026a090cc7ea5395f42cad..418929a82eb5b0e74aff05f6b7a5fa53ee9cb18a 100644 (file)
@@ -136,3 +136,9 @@ extern int __local_multiple_threads attribute_hidden;
 # define NO_CANCELLATION 1
 
 #endif
+
+#ifndef __ASSEMBLER__
+# define RTLD_SINGLE_THREAD_P \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+                                  header.multiple_threads) == 0, 1)
+#endif
index 65ff0639b61cc660ee288bd2551db85262e712a0..18ed4b522c20f901653aaeb484635261a8243214 100644 (file)
@@ -47,6 +47,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;
@@ -339,6 +340,26 @@ 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() \
+  GL(dl_wait_lookup_done) ()
+
 #endif /* __ASSEMBLER__ */
 
 #endif /* tls.h */
index b7d0f9b7e7d7b2cfd3a276f3c05b9469627f2984..3c2c0b7ea284b09f776660eedc55d8485a153581 100644 (file)
@@ -38,6 +38,7 @@
 #include <bits/libc-lock.h>
 #include <hp-timing.h>
 #include <tls.h>
+#include <rtld-lowlevel.h>
 
 __BEGIN_DECLS
 
@@ -376,8 +377,6 @@ struct rtld_global
     struct link_map *_ns_loaded;
     /* Number of object in the _dl_loaded list.  */
     unsigned int _ns_nloaded;
-    /* Array representing global scope.  */
-    struct r_scope_elem *_ns_global_scope[2];
     /* Direct pointer to the searchlist of the main object.  */
     struct r_scope_elem *_ns_main_searchlist;
     /* This is zero at program start to signal that the global scope map is
@@ -493,6 +492,8 @@ struct rtld_global
   EXTERN void (*_dl_init_static_tls) (struct link_map *);
 #endif
 
+  EXTERN void (*_dl_wait_lookup_done) (void);
+
 #ifdef SHARED
 };
 # define __rtld_global_attribute__
@@ -853,7 +854,9 @@ enum
     DL_LOOKUP_ADD_DEPENDENCY = 1,
     /* Return most recent version instead of default version for
        unversioned lookup.  */
-    DL_LOOKUP_RETURN_NEWEST = 2
+    DL_LOOKUP_RETURN_NEWEST = 2,
+    /* Set if the scopr lock in the UNDEF_MAP is taken.  */
+    DL_LOOKUP_SCOPE_LOCK = 4
   };
 
 /* Lookup versioned symbol.  */
index f07b784f2eaddb2235752dba789785d773a419ac..ba6a1e04ba4425a625719d8f74c7813ad17ad725 100644 (file)
@@ -2,6 +2,7 @@
 
 /* No multi-thread handling enabled.  */
 #define SINGLE_THREAD_P (1)
+#define RTLD_SINGLE_THREAD_P (1)
 #define LIBC_CANCEL_ASYNC()    0 /* Just a dummy value.  */
 #define LIBC_CANCEL_RESET(val) ((void)(val)) /* Nothing, but evaluate it.  */
 #define LIBC_CANCEL_HANDLED()  /* Nothing.  */