mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-12 16:20:06 +00:00
* 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:
parent
2acd01acb1
commit
df94b6412e
11
ChangeLog
11
ChangeLog
@ -1,5 +1,16 @@
|
||||
2007-05-18 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
* elf/dl-close.c (_dl_close_worker): When removing object from
|
||||
global scope, wait for all lookups to finish afterwards.
|
||||
* elf/dl-open.c (add_to_global): When global scope array must
|
||||
grow, allocate a new one and free old array only after all
|
||||
lookups finish.
|
||||
* elf/dl-runtime.c (_dl_fixup): Protect using global scope.
|
||||
(_dl_lookup_symbol_x): Likewise.
|
||||
* elf/dl-support.c: Define _dl_wait_lookup_done.
|
||||
* sysdeps/generic/ldsodefs.h (struct rtld_global): Add
|
||||
_dl_wait_lookup_done.
|
||||
|
||||
* malloc/malloc.c (do_check_chunk): Correct check for mmaped block
|
||||
not overlapping with arena.
|
||||
|
||||
|
@ -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. */
|
||||
|
@ -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. */
|
||||
|
@ -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. */
|
||||
|
@ -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;
|
||||
|
@ -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]
|
||||
|
@ -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);
|
||||
}
|
||||
|
26
nptl/init.c
26
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 <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
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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. */
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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__
|
||||
|
Loading…
Reference in New Issue
Block a user