* 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.
This commit is contained in:
Ulrich Drepper 2007-05-19 07:08:23 +00:00
parent 2acd01acb1
commit df94b6412e
14 changed files with 204 additions and 37 deletions

View File

@ -1,5 +1,16 @@
2007-05-18 Ulrich Drepper <drepper@redhat.com>
* elf/dl-close.c (_dl_close_worker): When removing object from
global scope, wait for all lookups to finish afterwards.
* elf/dl-open.c (add_to_global): When global scope array must
grow, allocate a new one and free old array only after all
lookups finish.
* elf/dl-runtime.c (_dl_fixup): Protect using global scope.
(_dl_lookup_symbol_x): Likewise.
* elf/dl-support.c: Define _dl_wait_lookup_done.
* sysdeps/generic/ldsodefs.h (struct rtld_global): Add
_dl_wait_lookup_done.
* malloc/malloc.c (do_check_chunk): Correct check for mmaped block
not overlapping with arena.

View File

@ -31,6 +31,7 @@
#include <sys/types.h>
#include <sys/mman.h>
#include <sysdep-cancel.h>
#include <tls.h>
/* Type of the constructor functions. */
@ -487,6 +488,9 @@ _dl_close_worker (struct link_map *map)
ns_msl->r_list[cnt - 1] = ns_msl->r_list[cnt];
--ns_msl->r_nlist;
if (!RTLD_SINGLE_THREAD_P)
THREAD_GSCOPE_WAIT ();
}
/* Remove the object from the dtv slotinfo array if it uses TLS. */

View File

@ -32,6 +32,7 @@
#include <bp-sym.h>
#include <caller.h>
#include <sysdep-cancel.h>
#include <tls.h>
#include <dl-dst.h>
@ -125,15 +126,25 @@ add_to_global (struct link_map *new)
{
/* We have to extend the existing array of link maps in the
main map. */
struct link_map **old_global
= GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list;
size_t new_nalloc = ((ns->_ns_global_scope_alloc + to_add) * 2);
new_global = (struct link_map **)
realloc (ns->_ns_main_searchlist->r_list,
((ns->_ns_global_scope_alloc + to_add + 8)
* sizeof (struct link_map *)));
malloc (new_nalloc * sizeof (struct link_map *));
if (new_global == NULL)
goto nomem;
ns->_ns_global_scope_alloc += to_add + 8;
memcpy (new_global, old_global,
ns->_ns_global_scope_alloc * sizeof (struct link_map *));
ns->_ns_global_scope_alloc = new_nalloc;
ns->_ns_main_searchlist->r_list = new_global;
if (!RTLD_SINGLE_THREAD_P)
THREAD_GSCOPE_WAIT ();
free (old_global);
}
/* Now add the new entries. */

View File

@ -26,6 +26,8 @@
#include <ldsodefs.h>
#include <sysdep-cancel.h>
#include "dynamic-link.h"
#include <tls.h>
#if (!defined ELF_MACHINE_NO_RELA && !defined ELF_MACHINE_PLT_REL) \
|| ELF_MACHINE_NO_REL
@ -97,10 +99,15 @@ _dl_fixup (
not necessary for objects which cannot be unloaded or when
we are not using any threads (yet). */
int flags = DL_LOOKUP_ADD_DEPENDENCY;
if (l->l_type == lt_loaded && !RTLD_SINGLE_THREAD_P)
if (!RTLD_SINGLE_THREAD_P)
{
__rtld_mrlock_lock (l->l_scope_lock);
flags |= DL_LOOKUP_SCOPE_LOCK;
THREAD_GSCOPE_SET_FLAG ();
if (l->l_type == lt_loaded)
{
__rtld_mrlock_lock (l->l_scope_lock);
flags |= DL_LOOKUP_SCOPE_LOCK;
}
}
result = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym, l->l_scope,
@ -109,6 +116,10 @@ _dl_fixup (
if ((flags & DL_LOOKUP_SCOPE_LOCK) != 0)
__rtld_mrlock_unlock (l->l_scope_lock);
/* We are done with the global scope. */
if (!RTLD_SINGLE_THREAD_P)
THREAD_GSCOPE_RESET_FLAG ();
/* Currently result contains the base load address (or link map)
of the object that defines sym. Now add in the symbol
offset. */
@ -191,10 +202,15 @@ _dl_profile_fixup (
not necessary for objects which cannot be unloaded or when
we are not using any threads (yet). */
int flags = DL_LOOKUP_ADD_DEPENDENCY;
if (l->l_type == lt_loaded && !RTLD_SINGLE_THREAD_P)
if (!RTLD_SINGLE_THREAD_P)
{
__rtld_mrlock_lock (l->l_scope_lock);
flags |= DL_LOOKUP_SCOPE_LOCK;
THREAD_GSCOPE_SET_FLAG ();
if (l->l_type == lt_loaded)
{
__rtld_mrlock_lock (l->l_scope_lock);
flags |= DL_LOOKUP_SCOPE_LOCK;
}
}
result = _dl_lookup_symbol_x (strtab + refsym->st_name, l,
@ -204,6 +220,10 @@ _dl_profile_fixup (
if ((flags & DL_LOOKUP_SCOPE_LOCK) != 0)
__rtld_mrlock_unlock (l->l_scope_lock);
/* We are done with the global scope. */
if (!RTLD_SINGLE_THREAD_P)
THREAD_GSCOPE_RESET_FLAG ();
/* Currently result contains the base load address (or link map)
of the object that defines sym. Now add in the symbol
offset. */

View File

@ -1,5 +1,5 @@
/* Support for dynamic linking code in static libc.
Copyright (C) 1996-2005, 2006 Free Software Foundation, Inc.
Copyright (C) 1996-2005, 2006, 2007 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@ -132,6 +132,9 @@ int (*_dl_make_stack_executable_hook) (void **) internal_function
= _dl_make_stack_executable;
/* Function in libpthread to wait for termination of lookups. */
void (*_dl_wait_lookup_done) (void);
#ifdef NEED_DL_SYSINFO
/* Needed for improved syscall handling on at least x86/Linux. */
uintptr_t _dl_sysinfo = DL_SYSINFO_DEFAULT;

View File

@ -1,3 +1,16 @@
2007-05-19 Ulrich Drepper <drepper@redhat.com>
* allocatestack.c (__wait_lookup_done): New function.
* sysdeps/pthread/pthread-functions.h (struct pthread_functions):
Add ptr_wait_lookup_done.
* init.c (pthread_functions): Initialize .ptr_wait_lookup_done.
* pthreadP.h: Declare __wait_lookup_done.
* sysdeps/i386/tls.h (tcbhead_t): Add gscope_flag.
Define macros to implement reference handling of global scope.
* sysdeps/x86_64/tls.h: Likewise.
* sysdeps/unix/sysv/linux/libc_pthread_init.c (__libc_pthread_init):
Initialize GL(dl_wait_lookup_done).
2007-05-17 Ulrich Drepper <drepper@redhat.com>
[BZ #4512]

View File

@ -996,3 +996,60 @@ __pthread_init_static_tls (struct link_map *map)
lll_unlock (stack_cache_lock);
}
void
attribute_hidden
__wait_lookup_done (void)
{
lll_lock (stack_cache_lock);
struct pthread *self = THREAD_SELF;
/* Iterate over the list with system-allocated threads first. */
list_t *runp;
list_for_each (runp, &stack_used)
{
struct pthread *t = list_entry (runp, struct pthread, list);
if (t == self || t->header.gscope_flag == THREAD_GSCOPE_FLAG_UNUSED)
continue;
int *const gscope_flagp = &t->header.gscope_flag;
/* We have to wait until this thread is done with the global
scope. First tell the thread that we are waiting and
possibly have to be woken. */
if (atomic_compare_and_exchange_bool_acq (gscope_flagp,
THREAD_GSCOPE_FLAG_WAIT,
THREAD_GSCOPE_FLAG_USED))
continue;
do
lll_futex_wait (gscope_flagp, THREAD_GSCOPE_FLAG_WAIT);
while (*gscope_flagp == THREAD_GSCOPE_FLAG_WAIT);
}
/* Now the list with threads using user-allocated stacks. */
list_for_each (runp, &__stack_user)
{
struct pthread *t = list_entry (runp, struct pthread, list);
if (t == self || t->header.gscope_flag == THREAD_GSCOPE_FLAG_UNUSED)
continue;
int *const gscope_flagp = &t->header.gscope_flag;
/* We have to wait until this thread is done with the global
scope. First tell the thread that we are waiting and
possibly have to be woken. */
if (atomic_compare_and_exchange_bool_acq (gscope_flagp,
THREAD_GSCOPE_FLAG_WAIT,
THREAD_GSCOPE_FLAG_USED))
continue;
do
lll_futex_wait (gscope_flagp, THREAD_GSCOPE_FLAG_WAIT);
while (*gscope_flagp == THREAD_GSCOPE_FLAG_WAIT);
}
lll_unlock (stack_cache_lock);
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
/* Copyright (C) 2002,2003,2004,2005,2006,2007 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
@ -35,27 +35,6 @@
#include <lowlevellock.h>
#ifndef __NR_set_tid_address
/* XXX For the time being... Once we can rely on the kernel headers
having the definition remove these lines. */
#if defined __s390__
# define __NR_set_tid_address 252
#elif defined __ia64__
# define __NR_set_tid_address 1233
#elif defined __i386__
# define __NR_set_tid_address 258
#elif defined __x86_64__
# define __NR_set_tid_address 218
#elif defined __powerpc__
# define __NR_set_tid_address 232
#elif defined __sparc__
# define __NR_set_tid_address 166
#else
# error "define __NR_set_tid_address"
#endif
#endif
/* Size and alignment of static TLS block. */
size_t __static_tls_size;
size_t __static_tls_align_m1;
@ -138,7 +117,8 @@ static const struct pthread_functions pthread_functions =
.ptr__nptl_deallocate_tsd = __nptl_deallocate_tsd,
.ptr__nptl_setxid = __nptl_setxid,
/* For now only the stack cache needs to be freed. */
.ptr_freeres = __free_stack_cache
.ptr_freeres = __free_stack_cache,
.ptr_wait_lookup_done = __wait_lookup_done
};
# define ptr_pthread_functions &pthread_functions
#else

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
/* Copyright (C) 2002,2003,2004,2005,2006,2007 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
@ -545,6 +545,8 @@ extern int __nptl_setxid (struct xid_command *cmdp) attribute_hidden;
extern void __free_stack_cache (void) attribute_hidden;
extern void __wait_lookup_done (void) attribute_hidden;
#ifdef SHARED
# define PTHREAD_STATIC_FN_REQUIRE(name)
#else

View File

@ -1,5 +1,5 @@
/* Definition for thread-local data handling. nptl/i386 version.
Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
Copyright (C) 2002,2003,2004,2005,2006,2007 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@ -27,6 +27,7 @@
# include <stdint.h>
# include <stdlib.h>
# include <list.h>
# include <sysdep.h>
/* Type for the dtv. */
@ -51,6 +52,7 @@ typedef struct
uintptr_t sysinfo;
uintptr_t stack_guard;
uintptr_t pointer_guard;
int gscope_flag;
} tcbhead_t;
# define TLS_MULTIPLE_THREADS_IN_TCB 1
@ -431,6 +433,35 @@ union user_desc_init
= THREAD_GETMEM (THREAD_SELF, header.pointer_guard))
/* Get and set the global scope generation counter in the TCB head. */
#define THREAD_GSCOPE_FLAG_UNUSED 0
#define THREAD_GSCOPE_FLAG_USED 1
#define THREAD_GSCOPE_FLAG_WAIT 2
#define THREAD_GSCOPE_RESET_FLAG() \
do \
{ int __res; \
asm volatile ("xchg %0, %%gs:%P1" \
: "=r" (__res) \
: "i" (offsetof (struct pthread, header.gscope_flag)), \
"0" (THREAD_GSCOPE_FLAG_UNUSED)); \
if (__res == THREAD_GSCOPE_FLAG_WAIT) \
lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1); \
} \
while (0)
#define THREAD_GSCOPE_SET_FLAG() \
THREAD_SETMEM (THREAD_SELF, header.gscope_flag, THREAD_GSCOPE_FLAG_USED)
#ifdef PTR_DEMANGLE
# define THREAD_GSCOPE_WAIT() \
do { void (*ptr) (void) = GL(dl_wait_lookup_done); \
PTR_DEMANGLE (ptr); \
ptr (); \
} while (0)
#else
# define THREAD_GSCOPE_WAIT() \
GL(dl_wait_lookup_done) ()
#endif
#endif /* __ASSEMBLER__ */
#endif /* tls.h */

View File

@ -97,7 +97,7 @@ struct pthread_functions
void (*ptr__nptl_deallocate_tsd) (void);
int (*ptr__nptl_setxid) (struct xid_command *);
void (*ptr_freeres) (void);
void (*ptr_wait_lookup_done) (int);
void (*ptr_wait_lookup_done) (void);
};
/* Variable in libc.so. */

View File

@ -26,6 +26,7 @@
#include <pthreadP.h>
#include <bits/libc-lock.h>
#include <sysdep.h>
#include <ldsodefs.h>
#ifdef TLS_MULTIPLE_THREADS_IN_TCB
@ -70,6 +71,12 @@ __libc_pthread_init (ptr, reclaim, functions)
dest->parr[cnt] = p;
}
__libc_pthread_functions_init = 1;
# ifdef RTLD_NOT_MANGLED
GL(dl_wait_lookup_done) = functions->ptr_wait_lookup_done;
# else
GL(dl_wait_lookup_done) = __libc_pthread_functions.ptr_wait_lookup_done;
# endif
#endif
#ifndef TLS_MULTIPLE_THREADS_IN_TCB

View File

@ -26,6 +26,7 @@
# include <stddef.h>
# include <stdint.h>
# include <stdlib.h>
# include <sysdep.h>
/* Type for the dtv. */
@ -47,6 +48,7 @@ typedef struct
dtv_t *dtv;
void *self; /* Pointer to the thread descriptor. */
int multiple_threads;
int gscope_flag;
uintptr_t sysinfo;
uintptr_t stack_guard;
uintptr_t pointer_guard;
@ -337,6 +339,30 @@ typedef struct
= THREAD_GETMEM (THREAD_SELF, header.pointer_guard))
/* Get and set the global scope generation counter in the TCB head. */
#define THREAD_GSCOPE_FLAG_UNUSED 0
#define THREAD_GSCOPE_FLAG_USED 1
#define THREAD_GSCOPE_FLAG_WAIT 2
#define THREAD_GSCOPE_RESET_FLAG() \
do \
{ int __res; \
asm volatile ("xchgl %0, %%fs:%P1" \
: "=r" (__res) \
: "i" (offsetof (struct pthread, header.gscope_flag)), \
"0" (THREAD_GSCOPE_FLAG_UNUSED)); \
if (__res == THREAD_GSCOPE_FLAG_WAIT) \
lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1); \
} \
while (0)
#define THREAD_GSCOPE_SET_FLAG() \
THREAD_SETMEM (THREAD_SELF, header.gscope_flag, THREAD_GSCOPE_FLAG_USED)
#define THREAD_GSCOPE_WAIT() \
do { void (*ptr) (void) = GL(dl_wait_lookup_done); \
PTR_DEMANGLE (ptr); \
ptr (); \
} while (0)
#endif /* __ASSEMBLER__ */
#endif /* tls.h */

View File

@ -486,6 +486,8 @@ struct rtld_global
EXTERN void (*_dl_init_static_tls) (struct link_map *);
EXTERN void (*_dl_wait_lookup_done) (void);
#ifdef SHARED
};
# define __rtld_global_attribute__