From 557fab43bd3cf75f87ba7efb65c9f4884e261a6c Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Sat, 23 Feb 2002 08:47:54 +0000 Subject: Update. 2002-02-23 Ulrich Drepper * csu/set-init.c: Moved to... * sysdeps/mach/hurd/set-init.c: ...here. New file. * csu/Makefile: Don't compile set-init. * sysdeps/mach/hurd/Makefile: Compile set-init for subdir csu. * sysdeps/mach/hurd/i386/init-first.c: Call __init_misc in addition to __libc_init. * sysdeps/mach/hurd/mips/init-first.c: Likewise. * sysdeps/mach/hurd/powerpc/init-first.c: Likewise. * sysdeps/unix/sysv/linux/init-first.c: Call __init_misc instead of __libc_init. * misc/init-misc.c: Always export __init_misc. Don't define hooks for __libc_subinit. --- ChangeLog | 15 ++++ csu/Makefile | 4 +- csu/set-init.c | 23 ----- linuxthreads/ChangeLog | 13 +++ linuxthreads/descr.h | 7 +- linuxthreads/internals.h | 1 + linuxthreads/manager.c | 130 +++++++++++++++++++++------ linuxthreads/pthread.c | 157 ++++++++++++++++++++++++++------- linuxthreads/sysdeps/i386/tls.h | 18 ++-- misc/init-misc.c | 16 +--- sysdeps/mach/hurd/Makefile | 1 + sysdeps/mach/hurd/i386/init-first.c | 2 + sysdeps/mach/hurd/mips/init-first.c | 4 +- sysdeps/mach/hurd/powerpc/init-first.c | 4 +- sysdeps/mach/hurd/set-init.c | 23 +++++ sysdeps/unix/sysv/linux/init-first.c | 4 +- 16 files changed, 314 insertions(+), 108 deletions(-) delete mode 100644 csu/set-init.c create mode 100644 sysdeps/mach/hurd/set-init.c diff --git a/ChangeLog b/ChangeLog index 41d839c..dbe013e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2002-02-23 Ulrich Drepper + + * csu/set-init.c: Moved to... + * sysdeps/mach/hurd/set-init.c: ...here. New file. + * csu/Makefile: Don't compile set-init. + * sysdeps/mach/hurd/Makefile: Compile set-init for subdir csu. + * sysdeps/mach/hurd/i386/init-first.c: Call __init_misc in addition + to __libc_init. + * sysdeps/mach/hurd/mips/init-first.c: Likewise. + * sysdeps/mach/hurd/powerpc/init-first.c: Likewise. + * sysdeps/unix/sysv/linux/init-first.c: Call __init_misc instead of + __libc_init. + * misc/init-misc.c: Always export __init_misc. Don't define hooks for + __libc_subinit. + 2002-02-22 Ulrich Drepper * elf/Versions: Add _dl_allocate_tls and _dl_deallocate_tls. diff --git a/csu/Makefile b/csu/Makefile index 012cbbe..994e2b2 100644 --- a/csu/Makefile +++ b/csu/Makefile @@ -59,9 +59,7 @@ before-compile += $(objpfx)abi-tag.h generated += abi-tag.h endif -ifeq (yes,$(gnu-ld)) -libc-init = set-init -else +ifneq (yes,$(gnu-ld)) libc-init = munch-init $(objpfx)munch-init.c: munch.awk munch-tmpl.c $(+subdir_inits) $(AWK) -f $< subdirs='$(+init_subdirs)' $(word 2,$^) > $@-t diff --git a/csu/set-init.c b/csu/set-init.c deleted file mode 100644 index f89a469..0000000 --- a/csu/set-init.c +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright (C) 1991, 1992, 1994, 1995, 1997 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. */ - -#include -#include - -DEFINE_HOOK_RUNNER (__libc_subinit, __libc_init, - (int argc, char **argv, char **envp), (argc, argv, envp)) diff --git a/linuxthreads/ChangeLog b/linuxthreads/ChangeLog index 762b29e..2fc0a62 100644 --- a/linuxthreads/ChangeLog +++ b/linuxthreads/ChangeLog @@ -1,3 +1,16 @@ +2002-02-23 Ulrich Drepper + + * descr.h (struct _pthread_descr_struct): Update p_header for TLS. + Add p_stackaddr element #if USE_TLS. + * internals.c: Include . + * manager.c: Integrate creating and handling of thread descriptor + for TLS. + * pthread.c: Likewise. + * sysdeps/i386/tls.h (tcbhead_t): Add self pointer. + Include only if TLS is really used. + (GET_DTV): New macro. + (TLS_INIT_TP): Initialize self pointer. + 2002-02-17 Andreas Schwab * signals.c (sigwait): Check for old sighandler being SIG_ERR, diff --git a/linuxthreads/descr.h b/linuxthreads/descr.h index a2cddb1..d0c31da 100644 --- a/linuxthreads/descr.h +++ b/linuxthreads/descr.h @@ -102,8 +102,10 @@ struct _pthread_descr_struct { /* XXX Remove this union for IA-64 style TLS module */ union { struct { - pthread_descr self; /* Pointer to this structure */ + void *tcb; /* Pointer to the TCB. This is not always + the address of this thread descriptor. */ union dtv *dtvp; + pthread_descr self; /* Pointer to this structure */ } data; void *__padding[16]; } p_header; @@ -158,6 +160,9 @@ struct _pthread_descr_struct { #if HP_TIMING_AVAIL hp_timing_t p_cpuclock_offset; /* Initial CPU clock for thread. */ #endif +#ifdef USE_TLS + char *p_stackaddr; /* Stack address. */ +#endif /* New elements must be added at the end. */ } __attribute__ ((aligned(32))); /* We need to align the structure so that doubles are aligned properly. This is 8 diff --git a/linuxthreads/internals.h b/linuxthreads/internals.h index 056e36d..209812c 100644 --- a/linuxthreads/internals.h +++ b/linuxthreads/internals.h @@ -23,6 +23,7 @@ #include #include +#include #include "descr.h" extern long int testandset (int *spinlock); diff --git a/linuxthreads/manager.c b/linuxthreads/manager.c index 9e4fcac..efbbf51 100644 --- a/linuxthreads/manager.c +++ b/linuxthreads/manager.c @@ -14,6 +14,7 @@ /* The "thread manager" thread: manages creation and termination of threads */ +#include #include #include #include @@ -27,6 +28,7 @@ #include #include /* for waitpid macros */ +#include #include "pthread.h" #include "internals.h" #include "spinlock.h" @@ -34,9 +36,23 @@ #include "semaphore.h" /* Array of active threads. Entry 0 is reserved for the initial thread. */ -struct pthread_handle_struct __pthread_handles[PTHREAD_THREADS_MAX] = -{ { __LOCK_INITIALIZER, &__pthread_initial_thread, 0}, - { __LOCK_INITIALIZER, &__pthread_manager_thread, 0}, /* All NULLs */ }; +struct pthread_handle_struct __pthread_handles[PTHREAD_THREADS_MAX] +#ifdef USE_TLS +# if __LT_SPINLOCK_INIT != 0 += { + { __LOCK_INITIALIZER, NULL, 0}, + { __LOCK_INITIALIZER, NULL, 0}, + /* All NULLs */ +} +# endif +#else += { + { __LOCK_INITIALIZER, &__pthread_initial_thread, 0}, + { __LOCK_INITIALIZER, &__pthread_manager_thread, 0}, + /* All NULLs */ +} +#endif +; /* For debugging purposes put the maximum number of threads in a variable. */ const int __linuxthreads_pthread_threads_max = PTHREAD_THREADS_MAX; @@ -60,6 +76,8 @@ volatile td_thr_events_t __pthread_threads_events; /* Pointer to thread descriptor with last event. */ volatile pthread_descr __pthread_last_event; +static pthread_descr manager_thread; + /* Mapping from stack segment to thread descriptor. */ /* Stack segment numbers are also indices into the __pthread_handles array. */ /* Stack segment number 0 is reserved for the initial thread. */ @@ -100,7 +118,7 @@ static void pthread_handle_exit(pthread_descr issuing_thread, int exitcode) __attribute__ ((noreturn)); static void pthread_reap_children(void); static void pthread_kill_all_threads(int sig, int main_thread_also); -static void pthread_for_each_thread(void *arg, +static void pthread_for_each_thread(void *arg, void (*fn)(void *, pthread_descr)); /* The server thread managing requests for thread creation and termination */ @@ -109,7 +127,8 @@ int __attribute__ ((noreturn)) __pthread_manager(void *arg) { - int reqfd = (int) (long int) arg; + pthread_descr self = manager_thread = arg; + int reqfd = __pthread_manager_reader; struct pollfd ufd; sigset_t manager_mask; int n; @@ -117,11 +136,11 @@ __pthread_manager(void *arg) /* If we have special thread_self processing, initialize it. */ #ifdef INIT_THREAD_SELF - INIT_THREAD_SELF(&__pthread_manager_thread, 1); + INIT_THREAD_SELF(self, 1); #endif /* Set the error variable. */ - __pthread_manager_thread.p_errnop = &__pthread_manager_thread.p_errno; - __pthread_manager_thread.p_h_errnop = &__pthread_manager_thread.p_h_errno; + self->p_errnop = &self->p_errno; + self->p_h_errnop = &self->p_h_errno; /* Block all signals except __pthread_sig_cancel and SIGTRAP */ sigfillset(&manager_mask); sigdelset(&manager_mask, __pthread_sig_cancel); /* for thread termination */ @@ -227,13 +246,13 @@ int __pthread_manager_event(void *arg) { /* If we have special thread_self processing, initialize it. */ #ifdef INIT_THREAD_SELF - INIT_THREAD_SELF(&__pthread_manager_thread, 1); + INIT_THREAD_SELF(arg, 1); #endif /* Get the lock the manager will free once all is correctly set up. */ - __pthread_lock (THREAD_GETMEM((&__pthread_manager_thread), p_lock), NULL); + __pthread_lock (THREAD_GETMEM(((pthread_descr) arg), p_lock), NULL); /* Free it immediately. */ - __pthread_unlock (THREAD_GETMEM((&__pthread_manager_thread), p_lock)); + __pthread_unlock (THREAD_GETMEM(((pthread_descr) arg), p_lock)); return __pthread_manager(arg); } @@ -270,7 +289,7 @@ pthread_start_thread(void *arg) __sched_setscheduler(THREAD_GETMEM(self, p_pid), THREAD_GETMEM(self, p_start_args.schedpolicy), &self->p_start_args.schedparam); - else if (__pthread_manager_thread.p_priority > 0) + else if (manager_thread->p_priority > 0) /* Default scheduling required, but thread manager runs in realtime scheduling: switch new thread to SCHED_OTHER policy */ { @@ -315,10 +334,14 @@ pthread_start_thread_event(void *arg) pthread_start_thread (arg); } +#if defined USE_TLS && !FLOATING_STACKS +# error "TLS can only work with floating stacks" +#endif + static int pthread_allocate_stack(const pthread_attr_t *attr, pthread_descr default_new_thread, int pagesize, - pthread_descr * out_new_thread, + char ** out_new_thread, char ** out_new_thread_bottom, char ** out_guardaddr, size_t * out_guardsize) @@ -328,12 +351,23 @@ static int pthread_allocate_stack(const pthread_attr_t *attr, char * guardaddr; size_t stacksize, guardsize; +#ifdef USE_TLS + /* TLS cannot work with fixed thread descriptor addresses. */ + assert (default_new_thread == NULL); +#endif + if (attr != NULL && attr->__stackaddr_set) { #ifdef _STACK_GROWS_UP /* The user provided a stack. */ +# ifdef USE_TLS + /* This value is not needed. */ + new_thread = (pthread_descr) attr->__stackaddr; + new_thread_bottom = (char *) new_thread; +# else new_thread = (pthread_descr) attr->__stackaddr; new_thread_bottom = (char *) (new_thread + 1); +# endif guardaddr = attr->__stackaddr + attr->__stacksize; guardsize = 0; #else @@ -347,8 +381,12 @@ static int pthread_allocate_stack(const pthread_attr_t *attr, addresses, stackaddr would be the lowest address in the stack segment, so that it is consistently close to the initial sp value. */ +# ifdef USE_TLS + new_thread = (pthread_descr) attr->__stackaddr; +# else new_thread = (pthread_descr) ((long)(attr->__stackaddr) & -sizeof(void *)) - 1; +# endif new_thread_bottom = (char *) attr->__stackaddr - attr->__stacksize; guardaddr = new_thread_bottom; guardsize = 0; @@ -356,16 +394,18 @@ static int pthread_allocate_stack(const pthread_attr_t *attr, #ifndef THREAD_SELF __pthread_nonstandard_stacks = 1; #endif +#ifndef USE_TLS /* Clear the thread data structure. */ memset (new_thread, '\0', sizeof (*new_thread)); +#endif } else { #ifdef NEED_SEPARATE_REGISTER_STACK - size_t granularity = 2 * pagesize; + const size_t granularity = 2 * pagesize; /* Try to make stacksize/2 a multiple of pagesize */ #else - size_t granularity = pagesize; + const size_t granularity = pagesize; #endif void *map_addr; @@ -397,22 +437,35 @@ static int pthread_allocate_stack(const pthread_attr_t *attr, mprotect (guardaddr, guardsize, PROT_NONE); new_thread_bottom = (char *) map_addr; +# ifdef USE_TLS + new_thread = ((pthread_descr) (new_thread_bottom + stacksize + + guardsize)); +# else new_thread = ((pthread_descr) (new_thread_bottom + stacksize + guardsize)) - 1; +# endif # elif _STACK_GROWS_DOWN guardaddr = map_addr; if (guardsize > 0) mprotect (guardaddr, guardsize, PROT_NONE); new_thread_bottom = (char *) map_addr + guardsize; +# ifdef USE_TLS + new_thread = ((pthread_descr) (new_thread_bottom + stacksize)); +# else new_thread = ((pthread_descr) (new_thread_bottom + stacksize)) - 1; +# endif # elif _STACK_GROWS_UP guardaddr = map_addr + stacksize; if (guardsize > 0) mprotect (guardaddr, guardsize, PROT_NONE); new_thread = (pthread_descr) map_addr; +# ifdef USE_TLS + new_thread_bottom = (char *) new_thread; +# else new_thread_bottom = (char *) (new_thread + 1); +# endif # else # error You must define a stack direction # endif /* Stack direction */ @@ -512,7 +565,7 @@ static int pthread_allocate_stack(const pthread_attr_t *attr, # endif /* !NEED_SEPARATE_REGISTER_STACK */ #endif /* !FLOATING_STACKS */ } - *out_new_thread = new_thread; + *out_new_thread = (char *) new_thread; *out_new_thread_bottom = new_thread_bottom; *out_guardaddr = guardaddr; *out_guardsize = guardsize; @@ -528,12 +581,19 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr, size_t sseg; int pid; pthread_descr new_thread; + char *stack_addr; char * new_thread_bottom; pthread_t new_thread_id; char *guardaddr = NULL; size_t guardsize = 0; int pagesize = __getpagesize(); - int saved_errno; + int saved_errno = 0; + +#ifdef USE_TLS + new_thread = _dl_allocate_tls (); + if (new_thread == NULL) + return EAGAIN; +#endif /* First check whether we have to change the policy and if yes, whether we can do this. Normally this should be done by examining the @@ -549,10 +609,16 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr, if (__pthread_handles[sseg].h_descr != NULL) continue; if (pthread_allocate_stack(attr, thread_segment(sseg), - pagesize, - &new_thread, &new_thread_bottom, + pagesize, &stack_addr, &new_thread_bottom, &guardaddr, &guardsize) == 0) - break; + { +#ifdef USE_TLS + new_thread->p_stackaddr = stack_addr; +#else + new_thread = (pthread_descr) stack_addr; +#endif + break; + } } __pthread_handles_num++; /* Allocate new thread identifier */ @@ -768,20 +834,32 @@ static void pthread_free(pthread_descr th) /* Free the stack and thread descriptor area */ char *guardaddr = th->p_guardaddr; #ifdef _STACK_GROWS_UP +# ifdef USE_TLS + size_t stacksize = guardaddr - th->p_stackaddr; +# else size_t stacksize = guardaddr - (char *)th; +# endif guardaddr = (char *)th; #else /* Guardaddr is always set, even if guardsize is 0. This allows us to compute everything else. */ +# ifdef USE_TLS + size_t stacksize = th->p_stackaddr - guardaddr - guardsize; +# else size_t stacksize = (char *)(th+1) - guardaddr - guardsize; -#ifdef NEED_SEPARATE_REGISTER_STACK +# endif +# ifdef NEED_SEPARATE_REGISTER_STACK /* Take account of the register stack, which is below guardaddr. */ guardaddr -= stacksize; stacksize *= 2; -#endif +# endif #endif /* Unmap the stack. */ munmap(guardaddr, stacksize + guardsize); + +#ifdef USE_TLS + _dl_deallocate_tls (th); +#endif } } @@ -896,7 +974,7 @@ static void pthread_kill_all_threads(int sig, int main_thread_also) } } -static void pthread_for_each_thread(void *arg, +static void pthread_for_each_thread(void *arg, void (*fn)(void *, pthread_descr)) { pthread_descr th; @@ -974,10 +1052,10 @@ void __pthread_manager_adjust_prio(int thread_prio) { struct sched_param param; - if (thread_prio <= __pthread_manager_thread.p_priority) return; + if (thread_prio <= manager_thread->p_priority) return; param.sched_priority = thread_prio < __sched_get_priority_max(SCHED_FIFO) ? thread_prio + 1 : thread_prio; - __sched_setscheduler(__pthread_manager_thread.p_pid, SCHED_FIFO, ¶m); - __pthread_manager_thread.p_priority = thread_prio; + __sched_setscheduler(manager_thread->p_pid, SCHED_FIFO, ¶m); + manager_thread->p_priority = thread_prio; } diff --git a/linuxthreads/pthread.c b/linuxthreads/pthread.c index 2901d9c..314360d 100644 --- a/linuxthreads/pthread.c +++ b/linuxthreads/pthread.c @@ -31,6 +31,7 @@ #include "spinlock.h" #include "restart.h" #include +#include /* We need the global/static resolver state here. */ #include @@ -47,12 +48,18 @@ extern struct __res_state _res; extern int _errno; extern int _h_errno; +#ifdef USE_TLS + +/* We need only a few variables. */ +static pthread_descr manager_thread; + +#else /* Descriptor of the initial thread */ struct _pthread_descr_struct __pthread_initial_thread = { { { - &__pthread_initial_thread /* pthread_descr self */ + .self = &__pthread_initial_thread /* pthread_descr self */ } }, &__pthread_initial_thread, /* pthread_descr p_nextlive */ @@ -106,10 +113,11 @@ struct _pthread_descr_struct __pthread_initial_thread = { variables, the p_pid and p_priority fields, and the address for identification. */ +#define manager_thread (&__pthread_manager_thread) struct _pthread_descr_struct __pthread_manager_thread = { { { - &__pthread_manager_thread /* pthread_descr self */ + .self = &__pthread_manager_thread /* pthread_descr self */ } }, NULL, /* pthread_descr p_nextlive */ @@ -158,11 +166,16 @@ struct _pthread_descr_struct __pthread_manager_thread = { NULL, /* pthread_readlock_info *p_readlock_free; */ 0 /* int p_untracked_readlock_count; */ }; +#endif /* Pointer to the main thread (the father of the thread manager thread) */ /* Originally, this is the initial thread, but this changes after fork() */ +#ifdef USE_TLS +pthread_descr __pthread_main_thread; +#else pthread_descr __pthread_main_thread = &__pthread_initial_thread; +#endif /* Limit between the stack of the initial thread (above) and the stacks of other threads (below). Aligned on a STACK_SIZE boundary. */ @@ -386,13 +399,44 @@ extern void *__dso_handle __attribute__ ((weak)); void __pthread_initialize_minimal(void) { +#ifdef USE_TLS + pthread_descr self = THREAD_SELF; + + /* The memory for the thread descriptor was allocated elsewhere as + part of the TLS allocation. We have to initialize the data + structure by hand. This initialization must mirror the struct + definition above. */ + self->p_header.data.self = self; + self->p_nextlive = self->p_prevlive = self; + self->p_tid = PTHREAD_THREADS_MAX; + self->p_lock = &__pthread_handles[0].h_lock; + self->p_errnop = &_errno; + self->p_h_errnop = &_h_errno; + /* self->p_start_args need not be initialized, it's all zero. */ + self->p_userstack = 1; +# if __LT_SPINLOCK_INIT != 0 + self->p_resume_count = (struct pthread_atomic) __ATOMIC_INITIALIZER; +# endif + + /* Another variable which points to the thread descriptor. */ + __pthread_main_thread = self; + + /* And fill in the pointer the the thread __pthread_handles array. */ + __pthread_handles[0].h_descr = self; +#else /* If we have special thread_self processing, initialize that for the main thread now. */ -#ifdef INIT_THREAD_SELF +# ifdef INIT_THREAD_SELF INIT_THREAD_SELF(&__pthread_initial_thread, 0); +# endif #endif + #if HP_TIMING_AVAIL +# ifdef USE_TLS + self->p_cpuclock_offset = GL(dl_cpuclock_offset); +# else __pthread_initial_thread.p_cpuclock_offset = GL(dl_cpuclock_offset); +# endif #endif } @@ -461,10 +505,17 @@ static void pthread_initialize(void) (char *)(((long)CURRENT_STACK_FRAME - 2 * STACK_SIZE) & ~(STACK_SIZE - 1)); # endif #endif +#ifdef USE_TLS + /* Update the descriptor for the initial thread. */ + THREAD_SETMEM (((pthread_descr) NULL), p_pid, __getpid()); + /* Likewise for the resolver state _res. */ + THREAD_SETMEM (((pthread_descr) NULL), p_resp, &_res); +#else /* Update the descriptor for the initial thread. */ __pthread_initial_thread.p_pid = __getpid(); /* Likewise for the resolver state _res. */ __pthread_initial_thread.p_resp = &_res; +#endif #ifdef __SIGRTMIN /* Initialize real-time signals. */ init_rtsigs (); @@ -513,6 +564,8 @@ int __pthread_initialize_manager(void) int manager_pipe[2]; int pid; struct pthread_request request; + int report_events; + pthread_descr tcb; #ifndef HAVE_Z_NODELETE if (__builtin_expect (&__dso_handle != NULL, 1)) @@ -535,37 +588,76 @@ int __pthread_initialize_manager(void) free(__pthread_manager_thread_bos); return -1; } + +#ifdef USE_TLS + /* Allocate memory for the thread descriptor and the dtv. */ + manager_thread = tcb = _dl_allocate_tls (); + if (tcb == NULL) { + free(__pthread_manager_thread_bos); + __libc_close(manager_pipe[0]); + __libc_close(manager_pipe[1]); + return -1; + } + + /* Initialize the descriptor. */ + tcb->p_header.data.self = tcb; + tcb->p_lock = &__pthread_handles[1].h_lock; + tcb->p_errnop = &tcb->p_errno; + tcb->p_start_args = (struct pthread_start_args) PTHREAD_START_ARGS_INITIALIZER(__pthread_manager); + tcb->p_nr = 1; +# if __LT_SPINLOCK_INIT != 0 + self->p_resume_count = (struct pthread_atomic) __ATOMIC_INITIALIZER; +# endif +#else + tcb = &__pthread_manager_thread; +#endif + + __pthread_manager_request = manager_pipe[1]; /* writing end */ + __pthread_manager_reader = manager_pipe[0]; /* reading end */ + /* Start the thread manager */ pid = 0; - if (__builtin_expect (__pthread_initial_thread.p_report_events, 0)) +#ifdef USE_TLS + report_events = THREAD_GETMEM (((pthread_descr) NULL), p_report_events); +#else + report_events = __pthread_initial_thread.p_report_events; +#endif + if (__builtin_expect (report_events, 0)) { /* It's a bit more complicated. We have to report the creation of the manager thread. */ int idx = __td_eventword (TD_CREATE); uint32_t mask = __td_eventmask (TD_CREATE); + uint32_t event_bits; - if ((mask & (__pthread_threads_events.event_bits[idx] - | __pthread_initial_thread.p_eventbuf.eventmask.event_bits[idx])) +#ifdef USE_TLS + event_bits = THREAD_GETMEM_NC (((pthread_descr) NULL), + p_eventbuf.eventmask.event_bits[idx]); +#else + event_bits = __pthread_initial_thread.p_eventbuf.eventmask.event_bits[idx]; +#endif + + if ((mask & (__pthread_threads_events.event_bits[idx] | event_bits)) != 0) { - __pthread_lock(__pthread_manager_thread.p_lock, NULL); + __pthread_lock(tcb->p_lock, NULL); #ifdef NEED_SEPARATE_REGISTER_STACK pid = __clone2(__pthread_manager_event, (void **) __pthread_manager_thread_bos, THREAD_MANAGER_STACK_SIZE, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, - (void *)(long)manager_pipe[0]); + tcb); #elif _STACK_GROWS_UP pid = __clone(__pthread_manager_event, (void **) __pthread_manager_thread_bos, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, - (void *)(long)manager_pipe[0]); + tcb); #else pid = __clone(__pthread_manager_event, (void **) __pthread_manager_thread_tos, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, - (void *)(long)manager_pipe[0]); + tcb); #endif if (pid != -1) @@ -574,19 +666,18 @@ int __pthread_initialize_manager(void) the newly created thread's data structure. We cannot let the new thread do this since we don't know whether it was already scheduled when we send the event. */ - __pthread_manager_thread.p_eventbuf.eventdata = - &__pthread_manager_thread; - __pthread_manager_thread.p_eventbuf.eventnum = TD_CREATE; - __pthread_last_event = &__pthread_manager_thread; - __pthread_manager_thread.p_tid = 2* PTHREAD_THREADS_MAX + 1; - __pthread_manager_thread.p_pid = pid; + tcb->p_eventbuf.eventdata = tcb; + tcb->p_eventbuf.eventnum = TD_CREATE; + __pthread_last_event = tcb; + tcb->p_tid = 2* PTHREAD_THREADS_MAX + 1; + tcb->p_pid = pid; /* Now call the function which signals the event. */ __linuxthreads_create_event (); } /* Now restart the thread. */ - __pthread_unlock(__pthread_manager_thread.p_lock); + __pthread_unlock(tcb->p_lock); } } @@ -595,16 +686,13 @@ int __pthread_initialize_manager(void) #ifdef NEED_SEPARATE_REGISTER_STACK pid = __clone2(__pthread_manager, (void **) __pthread_manager_thread_bos, THREAD_MANAGER_STACK_SIZE, - CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, - (void *)(long)manager_pipe[0]); + CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, tcb); #elif _STACK_GROWS_UP pid = __clone(__pthread_manager, (void **) __pthread_manager_thread_bos, - CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, - (void *)(long)manager_pipe[0]); + CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, tcb); #else pid = __clone(__pthread_manager, (void **) __pthread_manager_thread_tos, - CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, - (void *)(long)manager_pipe[0]); + CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, tcb); #endif } if (__builtin_expect (pid, 0) == -1) { @@ -613,10 +701,8 @@ int __pthread_initialize_manager(void) __libc_close(manager_pipe[1]); return -1; } - __pthread_manager_request = manager_pipe[1]; /* writing end */ - __pthread_manager_reader = manager_pipe[0]; /* reading end */ - __pthread_manager_thread.p_tid = 2* PTHREAD_THREADS_MAX + 1; - __pthread_manager_thread.p_pid = pid; + tcb->p_tid = 2* PTHREAD_THREADS_MAX + 1; + tcb->p_pid = pid; /* Make gdb aware of new thread manager */ if (__builtin_expect (__pthread_threads_debug, 0) && __pthread_sig_debug > 0) { @@ -725,7 +811,7 @@ static pthread_descr thread_self_stack(void) pthread_handle h; if (sp >= __pthread_manager_thread_bos && sp < __pthread_manager_thread_tos) - return &__pthread_manager_thread; + return manager_thread; h = __pthread_handles + 2; while (! (sp <= (char *) h->h_descr && sp >= h->h_bottom)) h++; @@ -805,7 +891,11 @@ static void pthread_onexit_process(int retcode, void *arg) children, so that timings for main thread account for all threads. */ if (self == __pthread_main_thread) { +#ifdef USE_TLS + waitpid(manager_thread->p_pid, NULL, __WCLONE); +#else waitpid(__pthread_manager_thread.p_pid, NULL, __WCLONE); +#endif /* Since all threads have been asynchronously terminated (possibly holding locks), free cannot be used any more. */ /*free (__pthread_manager_thread_bos);*/ @@ -850,7 +940,7 @@ static void pthread_handle_sigcancel(int sig) pthread_descr self = thread_self(); sigjmp_buf * jmpbuf; - if (self == &__pthread_manager_thread) + if (self == manager_thread) { #ifdef THREAD_SELF /* A new thread might get a cancel signal before it is fully @@ -858,7 +948,7 @@ static void pthread_handle_sigcancel(int sig) manager thread. Double check that this is really the manager thread. */ pthread_descr real_self = thread_self_stack(); - if (real_self == &__pthread_manager_thread) + if (real_self == manager_thread) { __pthread_manager_sighandler(sig); return; @@ -876,8 +966,13 @@ static void pthread_handle_sigcancel(int sig) if (__builtin_expect (__pthread_exit_requested, 0)) { /* Main thread should accumulate times for thread manager and its children, so that timings for main thread account for all threads. */ - if (self == __pthread_main_thread) + if (self == __pthread_main_thread) { +#ifdef USE_TLS + waitpid(manager_thread->p_pid, NULL, __WCLONE); +#else waitpid(__pthread_manager_thread.p_pid, NULL, __WCLONE); +#endif + } _exit(__pthread_exit_code); } if (__builtin_expect (THREAD_GETMEM(self, p_canceled), 0) diff --git a/linuxthreads/sysdeps/i386/tls.h b/linuxthreads/sysdeps/i386/tls.h index 8e1d469..d1975b2 100644 --- a/linuxthreads/sysdeps/i386/tls.h +++ b/linuxthreads/sysdeps/i386/tls.h @@ -32,15 +32,13 @@ typedef union dtv typedef struct { - void *tcb; + void *tcb; /* Pointer to the TCB. Not necessary the + thread descriptor used by libpthread. */ dtv_t *dtv; + void *self; /* Pointer to the thread descriptor. */ } tcbhead_t; -/* Get the thread descriptor definition. */ -#include - - /* We can support TLS only if the floating-stack support is available. */ #if defined FLOATING_STACKS && defined HAVE_TLS_SUPPORT @@ -50,6 +48,10 @@ typedef struct /* Signal that TLS support is available. */ # define USE_TLS 1 + +/* Get the thread descriptor definition. */ +# include + /* This is the size of the initial TCB. */ # define TLS_INIT_TCB_SIZE sizeof (tcbhead_t) @@ -77,6 +79,10 @@ typedef struct ({ struct _pthread_descr_struct *__descr; \ THREAD_SETMEM (__descr, p_header.data.dtvp, dtv); }) +/* Return dtv of given thread descriptor. */ +# define GET_DTV(descr) \ + (((tcbhead_t *) descr)->dtv) + /* Code to initially initialize the thread pointer. This might need special attention since 'errno' is not yet available and if the operation can cause a failure 'errno' must not be touched. */ @@ -89,6 +95,8 @@ typedef struct tcbhead_t *head = _descr; \ \ head->tcb = _descr; \ + /* For now the thread descriptor isat the same address. */ \ + head->self = _descr; \ \ asm ("pushl %%ebx\n\t" \ "movl $1, %%ebx\n\t" \ diff --git a/misc/init-misc.c b/misc/init-misc.c index 8091e8f..8b877c3 100644 --- a/misc/init-misc.c +++ b/misc/init-misc.c @@ -1,5 +1,5 @@ /* Define and initialize `__progname' et. al. - Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. + Copyright (C) 1994,1995,1996,1997,1998,2002 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 @@ -25,16 +25,6 @@ weak_alias (__progname_full, program_invocation_name) weak_alias (__progname, program_invocation_short_name) -#ifdef HAVE_GNU_LD -static -#endif /* HAVE_GNU_LD */ -void __init_misc (int argc, char **argv, char **envp) - __attribute__ ((unused)); - - -#ifdef HAVE_GNU_LD -static -#endif /* HAVE_GNU_LD */ void __init_misc (int argc, char **argv, char **envp) { @@ -48,7 +38,3 @@ __init_misc (int argc, char **argv, char **envp) __progname_full = argv[0]; } } - -#ifdef HAVE_GNU_LD -text_set_element (__libc_subinit, __init_misc); -#endif diff --git a/sysdeps/mach/hurd/Makefile b/sysdeps/mach/hurd/Makefile index f34a577..e12874f 100644 --- a/sysdeps/mach/hurd/Makefile +++ b/sysdeps/mach/hurd/Makefile @@ -186,6 +186,7 @@ endif ifeq ($(subdir),csu) +sysdep_routines += set-init extra-objs += static-start.o # We need special startup code for statically linked binaries. diff --git a/sysdeps/mach/hurd/i386/init-first.c b/sysdeps/mach/hurd/i386/init-first.c index e16a5cd..f8149da 100644 --- a/sysdeps/mach/hurd/i386/init-first.c +++ b/sysdeps/mach/hurd/i386/init-first.c @@ -29,6 +29,7 @@ extern void __mach_init (void); extern void __libc_init (int, char **, char **); +extern void __init_misc (int, char **, char **); #ifdef USE_NONOPTION_FLAGS extern void __getopt_clean_environment (char **); #endif @@ -64,6 +65,7 @@ posixland_init (int argc, char **argv, char **envp) __libc_argv = argv; __environ = envp; + __init_misc (argc, argv, envp); __libc_init (argc, argv, envp); #ifdef USE_NONOPTION_FLAGS diff --git a/sysdeps/mach/hurd/mips/init-first.c b/sysdeps/mach/hurd/mips/init-first.c index d0ab593..525f510 100644 --- a/sysdeps/mach/hurd/mips/init-first.c +++ b/sysdeps/mach/hurd/mips/init-first.c @@ -1,5 +1,5 @@ /* Initialization code run first thing by the ELF startup code. For Mips/Hurd. - Copyright (C) 1996, 1997, 1998, 2000, 2001 Free Software Foundation, Inc. + Copyright (C) 1996,1997,1998,2000,2001,2002 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 @@ extern void __mach_init (void); extern void __libc_init (int, char **, char **); +extern void __init_misc (int, char **, char **); #ifdef USE_NONOPTION_FLAGS extern void __getopt_clean_environment (char **); #endif @@ -106,6 +107,7 @@ init1 (int argc, char *arg0, ...) d->portarray, d->portarraysize, d->intarray, d->intarraysize); + __init_misc (argc, argv, __environ); __libc_init (argc, argv, __environ); #ifdef USE_NONOPTION_FLAGS diff --git a/sysdeps/mach/hurd/powerpc/init-first.c b/sysdeps/mach/hurd/powerpc/init-first.c index 25f5c53..c9ad660 100644 --- a/sysdeps/mach/hurd/powerpc/init-first.c +++ b/sysdeps/mach/hurd/powerpc/init-first.c @@ -1,5 +1,5 @@ /* Initialization code run first thing by the ELF startup code. PowerPC/Hurd. - Copyright (C) 1995,96,97,98,99,2000,01 Free Software Foundation, Inc. + Copyright (C) 1995-2001, 2002 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 @@ -29,6 +29,7 @@ extern void __mach_init (void); extern void __libc_init (int, char **, char **); +extern void __init_misc (int, char **, char **); #ifdef USE_NONOPTION_FLAGS extern void __getopt_clean_environment (char **); #endif @@ -69,6 +70,7 @@ posixland_init (int argc, char **argv, char **envp) __libc_argv = argv; __environ = envp; + __init_misc (argc, argv, envp); __libc_init (argc, argv, envp); #ifdef USE_NONOPTION_FLAGS diff --git a/sysdeps/mach/hurd/set-init.c b/sysdeps/mach/hurd/set-init.c new file mode 100644 index 0000000..f89a469 --- /dev/null +++ b/sysdeps/mach/hurd/set-init.c @@ -0,0 +1,23 @@ +/* Copyright (C) 1991, 1992, 1994, 1995, 1997 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. */ + +#include +#include + +DEFINE_HOOK_RUNNER (__libc_subinit, __libc_init, + (int argc, char **argv, char **envp), (argc, argv, envp)) diff --git a/sysdeps/unix/sysv/linux/init-first.c b/sysdeps/unix/sysv/linux/init-first.c index bffb0fa..1fb04bb 100644 --- a/sysdeps/unix/sysv/linux/init-first.c +++ b/sysdeps/unix/sysv/linux/init-first.c @@ -33,7 +33,7 @@ # include "dl-osinfo.h" #endif -extern void __libc_init (int, char **, char **); +extern void __init_misc (int, char **, char **); /* The function is called from assembly stubs the compiler can't see. */ static void init (int, char **, char **) __attribute__ ((unused)); @@ -89,7 +89,7 @@ init (int argc, char **argv, char **envp) __libc_init_secure (); #endif - __libc_init (argc, argv, envp); + __init_misc (argc, argv, envp); #ifdef USE_NONOPTION_FLAGS /* This is a hack to make the special getopt in GNU libc working. */ -- cgit v1.1