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