From 00a2f9aa41a4f2a441c3b9787ca1a7701632de5f Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Wed, 26 Aug 1998 16:00:46 +0000 Subject: Update. 1998-08-26 15:46 Ulrich Drepper * internals.h: Define THREAD_GETMEM and THREAD_SETMEM to default if not already defined. (struct _pthread_descr_struct): Add p_self and p_nr field. * manager.c (__pthread_handles): Define second element to point to manager thread. (__pthread_handles_num): Initialize to 2. (__pthread_manager): Use INIT_THREAD_SELF with two arguments. (pthread_start_thread): Likewise. (pthread_handle_create): Start search for free slot at entry 2. Initialize new fields p_self and p_nr. Call __clone with CLONE_PTRACE if available. (pthread_free): Call FREE_THREAD_SELF if available. * pthread.c (__pthread_initial_thread): Initialize new fields. (__pthread_manager_thread): Likewise. (__pthread_initialize_manager): Call __clone with CLONE_PTRACE. * cancel.c: Use THREAD_GETMEM and THREAD_SETMEM to access the elements of the thread descriptor. * condvar.c: Likewise. * errno.c: Likewise. * join.c: Likewise. * manager.c: Likewise. * pthread.c: Likewise. * ptlongjmp.c: Likewise. * semaphore.c: Likewise. * signals.c: Likewise. * specific.c: Likewise. * spinlock.c: Likewise. * sysdeps/alpha/pt-machine.h (INIT_THREAD_SELF): Add extra parameter. * sysdeps/i386/useldt.h: New file. * sysdeps/i386/i686/pt-machine.h: Show how to use this file. * sysdeps/sparc/sparc32/pt-machine.h: Define THREAD_GETMEM and THREAD_SETMEM using __thread_self. * sysdeps/sparc/sparc64/pt-machine.h: Likewise. --- linuxthreads/ChangeLog | 40 ++++++++ linuxthreads/cancel.c | 50 +++++----- linuxthreads/condvar.c | 21 ++-- linuxthreads/errno.c | 4 +- linuxthreads/internals.h | 9 ++ linuxthreads/join.c | 15 +-- linuxthreads/manager.c | 32 +++--- linuxthreads/pthread.c | 94 +++++++++++++----- linuxthreads/ptlongjmp.c | 9 +- linuxthreads/semaphore.c | 5 +- linuxthreads/signals.c | 27 +++--- linuxthreads/specific.c | 28 +++--- linuxthreads/spinlock.c | 2 +- linuxthreads/sysdeps/alpha/pt-machine.h | 4 +- linuxthreads/sysdeps/i386/i686/pt-machine.h | 4 + linuxthreads/sysdeps/i386/useldt.h | 124 ++++++++++++++++++++++++ linuxthreads/sysdeps/sparc/sparc32/pt-machine.h | 6 +- linuxthreads/sysdeps/sparc/sparc64/pt-machine.h | 6 +- 18 files changed, 368 insertions(+), 112 deletions(-) create mode 100644 linuxthreads/sysdeps/i386/useldt.h (limited to 'linuxthreads') diff --git a/linuxthreads/ChangeLog b/linuxthreads/ChangeLog index 5b4dcbd64a..00f52d6413 100644 --- a/linuxthreads/ChangeLog +++ b/linuxthreads/ChangeLog @@ -1,3 +1,43 @@ +1998-08-26 15:46 Ulrich Drepper + + * internals.h: Define THREAD_GETMEM and THREAD_SETMEM to default if + not already defined. + (struct _pthread_descr_struct): Add p_self and p_nr field. + * manager.c (__pthread_handles): Define second element to point + to manager thread. + (__pthread_handles_num): Initialize to 2. + (__pthread_manager): Use INIT_THREAD_SELF with two arguments. + (pthread_start_thread): Likewise. + (pthread_handle_create): Start search for free slot at entry 2. + Initialize new fields p_self and p_nr. + Call __clone with CLONE_PTRACE if available. + (pthread_free): Call FREE_THREAD_SELF if available. + * pthread.c (__pthread_initial_thread): Initialize new fields. + (__pthread_manager_thread): Likewise. + (__pthread_initialize_manager): Call __clone with CLONE_PTRACE. + + * cancel.c: Use THREAD_GETMEM and THREAD_SETMEM to access the + elements of the thread descriptor. + * condvar.c: Likewise. + * errno.c: Likewise. + * join.c: Likewise. + * manager.c: Likewise. + * pthread.c: Likewise. + * ptlongjmp.c: Likewise. + * semaphore.c: Likewise. + * signals.c: Likewise. + * specific.c: Likewise. + * spinlock.c: Likewise. + + * sysdeps/alpha/pt-machine.h (INIT_THREAD_SELF): Add extra parameter. + + * sysdeps/i386/useldt.h: New file. + * sysdeps/i386/i686/pt-machine.h: Show how to use this file. + + * sysdeps/sparc/sparc32/pt-machine.h: Define THREAD_GETMEM and + THREAD_SETMEM using __thread_self. + * sysdeps/sparc/sparc64/pt-machine.h: Likewise. + 1998-08-24 Geoff Keating * spinlock.c (__pthread_lock): Reset p_nextwaiting to NULL if it diff --git a/linuxthreads/cancel.c b/linuxthreads/cancel.c index eda5d88154..e9cb10cc7c 100644 --- a/linuxthreads/cancel.c +++ b/linuxthreads/cancel.c @@ -25,11 +25,11 @@ int pthread_setcancelstate(int state, int * oldstate) pthread_descr self = thread_self(); if (state < PTHREAD_CANCEL_ENABLE || state > PTHREAD_CANCEL_DISABLE) return EINVAL; - if (oldstate != NULL) *oldstate = self->p_cancelstate; - self->p_cancelstate = state; - if (self->p_canceled && - self->p_cancelstate == PTHREAD_CANCEL_ENABLE && - self->p_canceltype == PTHREAD_CANCEL_ASYNCHRONOUS) + if (oldstate != NULL) *oldstate = THREAD_GETMEM(self, p_cancelstate); + THREAD_SETMEM(self, p_cancelstate, state); + if (THREAD_GETMEM(self, p_canceled) && + THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE && + THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS) pthread_exit(PTHREAD_CANCELED); return 0; } @@ -39,11 +39,11 @@ int pthread_setcanceltype(int type, int * oldtype) pthread_descr self = thread_self(); if (type < PTHREAD_CANCEL_DEFERRED || type > PTHREAD_CANCEL_ASYNCHRONOUS) return EINVAL; - if (oldtype != NULL) *oldtype = self->p_canceltype; - self->p_canceltype = type; - if (self->p_canceled && - self->p_cancelstate == PTHREAD_CANCEL_ENABLE && - self->p_canceltype == PTHREAD_CANCEL_ASYNCHRONOUS) + if (oldtype != NULL) *oldtype = THREAD_GETMEM(self, p_canceltype); + THREAD_SETMEM(self, p_canceltype, type); + if (THREAD_GETMEM(self, p_canceled) && + THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE && + THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS) pthread_exit(PTHREAD_CANCELED); return 0; } @@ -68,7 +68,8 @@ int pthread_cancel(pthread_t thread) void pthread_testcancel(void) { pthread_descr self = thread_self(); - if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) + if (THREAD_GETMEM(self, p_canceled) + && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) pthread_exit(PTHREAD_CANCELED); } @@ -78,8 +79,8 @@ void _pthread_cleanup_push(struct _pthread_cleanup_buffer * buffer, pthread_descr self = thread_self(); buffer->routine = routine; buffer->arg = arg; - buffer->prev = self->p_cleanup; - self->p_cleanup = buffer; + buffer->prev = THREAD_GETMEM(self, p_cleanup); + THREAD_SETMEM(self, p_cleanup, buffer); } void _pthread_cleanup_pop(struct _pthread_cleanup_buffer * buffer, @@ -87,7 +88,7 @@ void _pthread_cleanup_pop(struct _pthread_cleanup_buffer * buffer, { pthread_descr self = thread_self(); if (execute) buffer->routine(buffer->arg); - self->p_cleanup = buffer->prev; + THREAD_SETMEM(self, p_cleanup, buffer->prev); } void _pthread_cleanup_push_defer(struct _pthread_cleanup_buffer * buffer, @@ -96,10 +97,10 @@ void _pthread_cleanup_push_defer(struct _pthread_cleanup_buffer * buffer, pthread_descr self = thread_self(); buffer->routine = routine; buffer->arg = arg; - buffer->canceltype = self->p_canceltype; - buffer->prev = self->p_cleanup; - self->p_canceltype = PTHREAD_CANCEL_DEFERRED; - self->p_cleanup = buffer; + buffer->canceltype = THREAD_GETMEM(self, p_canceltype); + buffer->prev = THREAD_GETMEM(self, p_cleanup); + THREAD_SETMEM(self, p_canceltype, PTHREAD_CANCEL_DEFERRED); + THREAD_SETMEM(self, p_cleanup, buffer); } void _pthread_cleanup_pop_restore(struct _pthread_cleanup_buffer * buffer, @@ -107,11 +108,11 @@ void _pthread_cleanup_pop_restore(struct _pthread_cleanup_buffer * buffer, { pthread_descr self = thread_self(); if (execute) buffer->routine(buffer->arg); - self->p_cleanup = buffer->prev; - self->p_canceltype = buffer->canceltype; - if (self->p_canceled && - self->p_cancelstate == PTHREAD_CANCEL_ENABLE && - self->p_canceltype == PTHREAD_CANCEL_ASYNCHRONOUS) + THREAD_SETMEM(self, p_cleanup, buffer->prev); + THREAD_SETMEM(self, p_canceltype, buffer->canceltype); + if (THREAD_GETMEM(self, p_canceled) && + THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE && + THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS) pthread_exit(PTHREAD_CANCELED); } @@ -119,7 +120,8 @@ void __pthread_perform_cleanup(void) { pthread_descr self = thread_self(); struct _pthread_cleanup_buffer * c; - for (c = self->p_cleanup; c != NULL; c = c->prev) c->routine(c->arg); + for (c = THREAD_GETMEM(self, p_cleanup); c != NULL; c = c->prev) + c->routine(c->arg); } #ifndef PIC diff --git a/linuxthreads/condvar.c b/linuxthreads/condvar.c index 480a8e426e..773d7144f0 100644 --- a/linuxthreads/condvar.c +++ b/linuxthreads/condvar.c @@ -50,7 +50,8 @@ int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) suspend_with_cancellation(self); pthread_mutex_lock(mutex); /* This is a cancellation point */ - if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) { + if (THREAD_GETMEM(self, p_canceled) + && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) { /* Remove ourselves from the waiting queue if we're still on it */ __pthread_lock(&cond->c_lock); remove_from_queue(&cond->c_waiting, self); @@ -77,11 +78,12 @@ pthread_cond_timedwait_relative(pthread_cond_t *cond, pthread_mutex_unlock(mutex); /* Set up a longjmp handler for the restart and cancel signals */ if (sigsetjmp(jmpbuf, 1) == 0) { - self->p_signal_jmp = &jmpbuf; - self->p_cancel_jmp = &jmpbuf; - self->p_signal = 0; + THREAD_SETMEM(self, p_signal_jmp, &jmpbuf); + THREAD_SETMEM(self, p_cancel_jmp, &jmpbuf); + THREAD_SETMEM(self, p_signal, 0); /* Check for cancellation */ - if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) { + if (THREAD_GETMEM(self, p_canceled) + && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) { retsleep = -1; } else { /* Unblock the restart signal */ @@ -96,14 +98,15 @@ pthread_cond_timedwait_relative(pthread_cond_t *cond, } else { retsleep = -1; } - self->p_signal_jmp = NULL; - self->p_cancel_jmp = NULL; + THREAD_SETMEM(self, p_signal_jmp, NULL); + THREAD_SETMEM(self, p_cancel_jmp, NULL); /* Here, either the condition was signaled (self->p_signal != 0) or we got canceled (self->p_canceled != 0) or the timeout occurred (retsleep == 0) or another interrupt occurred (retsleep == -1) */ /* This is a cancellation point */ - if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) { + if (THREAD_GETMEM(self, p_canceled) + && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) { __pthread_lock(&cond->c_lock); remove_from_queue(&cond->c_waiting, self); __pthread_unlock(&cond->c_lock); @@ -111,7 +114,7 @@ pthread_cond_timedwait_relative(pthread_cond_t *cond, pthread_exit(PTHREAD_CANCELED); } /* If not signaled: also remove ourselves and return an error code */ - if (self->p_signal == 0) { + if (THREAD_GETMEM(self, p_signal) == 0) { __pthread_lock(&cond->c_lock); remove_from_queue(&cond->c_waiting, self); __pthread_unlock(&cond->c_lock); diff --git a/linuxthreads/errno.c b/linuxthreads/errno.c index 3619aa87b6..746474860c 100644 --- a/linuxthreads/errno.c +++ b/linuxthreads/errno.c @@ -22,11 +22,11 @@ int * __errno_location() { pthread_descr self = thread_self(); - return self->p_errnop; + return THREAD_GETMEM (self, p_errnop); } int * __h_errno_location() { pthread_descr self = thread_self(); - return self->p_h_errnop; + return THREAD_GETMEM (self, p_h_errnop); } diff --git a/linuxthreads/internals.h b/linuxthreads/internals.h index 62c14c606d..d418fe2211 100644 --- a/linuxthreads/internals.h +++ b/linuxthreads/internals.h @@ -25,6 +25,13 @@ #include "pt-machine.h" +#ifndef THREAD_GETMEM +# define THREAD_GETMEM(descr, member) descr->member +#endif +#ifndef THREAD_SETMEM +# define THREAD_SETMEM(descr, member, value) descr->member = (value) +#endif + /* Arguments passed to thread creation routine */ struct pthread_start_args { @@ -90,6 +97,8 @@ struct _pthread_descr_struct { int p_userstack; /* nonzero if the user provided the stack */ void *p_guardaddr; /* address of guard area or NULL */ size_t p_guardsize; /* size of guard area */ + pthread_descr p_self; /* Pointer to this structure */ + int p_nr; /* Index of descriptor in __pthread_handles */ }; /* The type of thread handles. */ diff --git a/linuxthreads/join.c b/linuxthreads/join.c index 4fadd85299..482f0d1dcc 100644 --- a/linuxthreads/join.c +++ b/linuxthreads/join.c @@ -30,18 +30,18 @@ void pthread_exit(void * retval) /* Reset the cancellation flag to avoid looping if the cleanup handlers contain cancellation points */ - self->p_canceled = 0; + THREAD_SETMEM(self, p_canceled, 0); /* Call cleanup functions and destroy the thread-specific data */ __pthread_perform_cleanup(); __pthread_destroy_specifics(); /* Store return value */ - __pthread_lock(self->p_lock); - self->p_retval = retval; + __pthread_lock(THREAD_GETMEM(self, p_lock)); + THREAD_SETMEM(self, p_retval, retval); /* Say that we've terminated */ - self->p_terminated = 1; + THREAD_SETMEM(self, p_terminated, 1); /* See if someone is joining on us */ - joining = self->p_joining; - __pthread_unlock(self->p_lock); + joining = THREAD_GETMEM(self, p_joining); + __pthread_unlock(THREAD_GETMEM(self, p_lock)); /* Restart joining thread if any */ if (joining != NULL) restart(joining); /* If this is the initial thread, block until all threads have terminated. @@ -86,7 +86,8 @@ int pthread_join(pthread_t thread_id, void ** thread_return) __pthread_unlock(&handle->h_lock); suspend_with_cancellation(self); /* This is a cancellation point */ - if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) { + if (THREAD_GETMEM(self, p_canceled) + && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) { th->p_joining = NULL; pthread_exit(PTHREAD_CANCELED); } diff --git a/linuxthreads/manager.c b/linuxthreads/manager.c index 41acf01b29..d145395407 100644 --- a/linuxthreads/manager.c +++ b/linuxthreads/manager.c @@ -36,14 +36,15 @@ /* 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}, /* All NULLs */ }; +{ { LOCK_INITIALIZER, &__pthread_initial_thread, 0}, + { LOCK_INITIALIZER, &__pthread_manager_thread, 0}, /* All NULLs */ }; /* Indicate whether at least one thread has a user-defined stack (if 1), or if all threads have stacks supplied by LinuxThreads (if 0). */ int __pthread_nonstandard_stacks = 0; /* Number of active entries in __pthread_handles (used by gdb) */ -volatile int __pthread_handles_num = 1; +volatile int __pthread_handles_num = 2; /* Whether to use debugger additional actions for thread creation (set to 1 by gdb) */ @@ -95,7 +96,7 @@ int __pthread_manager(void *arg) /* If we have special thread_self processing, initialize it. */ #ifdef INIT_THREAD_SELF - INIT_THREAD_SELF(&__pthread_manager_thread); + INIT_THREAD_SELF(&__pthread_manager_thread, 1); #endif /* Set the error variable. */ __pthread_manager_thread.p_errnop = &__pthread_manager_thread.p_errno; @@ -179,17 +180,18 @@ static int pthread_start_thread(void *arg) void * outcome; /* Initialize special thread_self processing, if any. */ #ifdef INIT_THREAD_SELF - INIT_THREAD_SELF(self); + INIT_THREAD_SELF(self, self->p_nr); #endif /* Make sure our pid field is initialized, just in case we get there before our father has initialized it. */ - self->p_pid = __getpid(); + THREAD_SETMEM(self, p_pid, __getpid()); /* Initial signal mask is that of the creating thread. (Otherwise, we'd just inherit the mask of the thread manager.) */ sigprocmask(SIG_SETMASK, &self->p_start_args.mask, NULL); /* Set the scheduling policy and priority for the new thread, if needed */ - if (self->p_start_args.schedpolicy >= 0) - __sched_setscheduler(self->p_pid, self->p_start_args.schedpolicy, + if (THREAD_GETMEM(self, p_start_args.schedpolicy) >= 0) + __sched_setscheduler(THREAD_GETMEM(self, p_pid), + THREAD_GETMEM(self, p_start_args.schedpolicy), &self->p_start_args.schedparam); /* Make gdb aware of new thread */ if (__pthread_threads_debug) { @@ -200,7 +202,8 @@ static int pthread_start_thread(void *arg) suspend(self); } /* Run the thread code */ - outcome = self->p_start_args.start_routine(self->p_start_args.arg); + outcome = self->p_start_args.start_routine(THREAD_GETMEM(self, + p_start_args.arg)); /* Exit with the given return value */ pthread_exit(outcome); return 0; @@ -298,7 +301,7 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr, if (attr != NULL && attr->schedpolicy != SCHED_OTHER && geteuid () != 0) return EPERM; /* Find a free segment for the thread, and allocate a stack if needed */ - for (sseg = 1; ; sseg++) + for (sseg = 2; ; sseg++) { if (sseg >= PTHREAD_THREADS_MAX) return EAGAIN; @@ -340,6 +343,8 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr, new_thread->p_userstack = attr != NULL && attr->stackaddr_set; memset (new_thread->p_specific, '\0', PTHREAD_KEY_1STLEVEL_SIZE * sizeof (new_thread->p_specific[0])); + new_thread->p_self = new_thread; + new_thread->p_nr = sseg; /* Initialize the thread handle */ __pthread_init_lock(&__pthread_handles[sseg].h_lock); __pthread_handles[sseg].h_descr = new_thread; @@ -370,8 +375,10 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr, /* Do the cloning */ pid = __clone(pthread_start_thread, (void **) new_thread, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | - __pthread_sig_restart, - new_thread); +#ifdef CLONE_PTRACE + CLONE_PTRACE | +#endif + __pthread_sig_restart, new_thread); /* Check if cloning succeeded */ if (pid == -1) { /* Free the stack if we allocated it */ @@ -414,6 +421,9 @@ static void pthread_free(pthread_descr th) handle->h_descr = NULL; handle->h_bottom = (char *)(-1L); __pthread_unlock(&handle->h_lock); +#ifdef FREE_THREAD_SELF + FREE_THREAD_SELF(th, th->p_nr); +#endif /* One fewer threads in __pthread_handles */ __pthread_handles_num--; /* If initial thread, nothing to free */ diff --git a/linuxthreads/pthread.c b/linuxthreads/pthread.c index 313220e7a0..c7cfdac796 100644 --- a/linuxthreads/pthread.c +++ b/linuxthreads/pthread.c @@ -58,7 +58,13 @@ struct _pthread_descr_struct __pthread_initial_thread = { NULL, /* char * p_in_sighandler */ 0, /* char p_sigwaiting */ PTHREAD_START_ARGS_INITIALIZER, /* struct pthread_start_args p_start_args */ - {NULL} /* void * p_specific[PTHREAD_KEYS_MAX] */ + {NULL}, /* void ** p_specific[PTHREAD_KEY_1STLEVEL_SIZE] */ + {NULL}, /* void * p_libc_specific[_LIBC_TSD_KEY_N] */ + 0, /* int p_userstack */ + NULL, /* void * p_guardaddr */ + 0, /* size_t p_guardsize */ + &__pthread_initial_thread, /* pthread_descr p_self */ + 0 /* Always index 0 */ }; /* Descriptor of the manager thread; none of this is used but the error @@ -86,14 +92,20 @@ struct _pthread_descr_struct __pthread_manager_thread = { 0, /* char p_cancelstate */ 0, /* char p_canceltype */ 0, /* char p_canceled */ - NULL, /* int *p_errnop */ + &__pthread_manager_thread.p_errno, /* int *p_errnop */ 0, /* int p_errno */ NULL, /* int *p_h_errnop */ 0, /* int p_h_errno */ NULL, /* char * p_in_sighandler */ 0, /* char p_sigwaiting */ PTHREAD_START_ARGS_INITIALIZER, /* struct pthread_start_args p_start_args */ - {NULL} /* void * p_specific[PTHREAD_KEYS_MAX] */ + {NULL}, /* void ** p_specific[PTHREAD_KEY_1STLEVEL_SIZE] */ + {NULL}, /* void * p_libc_specific[_LIBC_TSD_KEY_N] */ + 0, /* int p_userstack */ + NULL, /* void * p_guardaddr */ + 0, /* size_t p_guardsize */ + &__pthread_manager_thread, /* pthread_descr p_self */ + 1 /* Always index 1 */ }; /* Pointer to the main thread (the father of the thread manager thread) */ @@ -145,8 +157,13 @@ extern int _h_errno; /* Forward declarations */ static void pthread_exit_process(int retcode, void *arg); +#ifndef __i386__ static void pthread_handle_sigcancel(int sig); static void pthread_handle_sigrestart(int sig); +#else +static void pthread_handle_sigcancel(int sig, struct sigcontext ctx); +static void pthread_handle_sigrestart(int sig, struct sigcontext ctx); +#endif /* Initialize the pthread library. Initialization is split in two functions: @@ -189,7 +206,7 @@ static void pthread_initialize(void) /* If we have special thread_self processing, initialize that for the main thread now. */ #ifdef INIT_THREAD_SELF - INIT_THREAD_SELF(&__pthread_initial_thread); + INIT_THREAD_SELF(&__pthread_initial_thread, 0); #endif /* The errno/h_errno variable of the main thread are the global ones. */ __pthread_initial_thread.p_errnop = &_errno; @@ -209,12 +226,20 @@ static void pthread_initialize(void) /* Setup signal handlers for the initial thread. Since signal handlers are shared between threads, these settings will be inherited by all other threads. */ +#ifndef __i386__ sa.sa_handler = pthread_handle_sigrestart; +#else + sa.sa_handler = (__sighandler_t) pthread_handle_sigrestart; +#endif sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; /* does not matter for regular threads, but better for the thread manager */ __sigaction(__pthread_sig_restart, &sa, NULL); +#ifndef __i386__ sa.sa_handler = pthread_handle_sigcancel; +#else + sa.sa_handler = (__sighandler_t) pthread_handle_sigcancel; +#endif sa.sa_flags = 0; __sigaction(__pthread_sig_cancel, &sa, NULL); @@ -254,8 +279,11 @@ int __pthread_initialize_manager(void) } /* Start the thread manager */ 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 +#ifdef CLONE_PTRACE + | CLONE_PTRACE +#endif + , (void *)(long)manager_pipe[0]); if (pid == -1) { free(__pthread_manager_thread_bos); __libc_close(manager_pipe[0]); @@ -292,8 +320,9 @@ int __pthread_create_2_1(pthread_t *thread, const pthread_attr_t *attr, &request.req_args.create.mask); __libc_write(__pthread_manager_request, (char *) &request, sizeof(request)); suspend(self); - if (self->p_retcode == 0) *thread = (pthread_t) self->p_retval; - return self->p_retcode; + if (THREAD_GETMEM(self, p_retcode) == 0) + *thread = (pthread_t) THREAD_GETMEM(self, p_retval); + return THREAD_GETMEM(self, p_retcode); } #if defined HAVE_ELF && defined PIC && defined DO_VERSIONING @@ -330,7 +359,7 @@ strong_alias (__pthread_create_2_1, pthread_create) pthread_t pthread_self(void) { pthread_descr self = thread_self(); - return self->p_tid; + return THREAD_GETMEM(self, p_tid); } int pthread_equal(pthread_t thread1, pthread_t thread2) @@ -347,9 +376,9 @@ pthread_descr __pthread_find_self() char * sp = CURRENT_STACK_FRAME; pthread_handle h; - /* __pthread_handles[0] is the initial thread, handled specially in - thread_self(), so start at 1 */ - h = __pthread_handles + 1; + /* __pthread_handles[0] is the initial thread, __pthread_handles[1] is + the manager threads handled specially in thread_self(), so start at 2 */ + h = __pthread_handles + 2; while (! (sp <= (char *) h->h_descr && sp >= h->h_bottom)) h++; return h->h_descr; } @@ -428,14 +457,23 @@ static void pthread_exit_process(int retcode, void *arg) For the thread manager thread, redirect the signal to __pthread_manager_sighandler. */ +#ifndef __i386__ static void pthread_handle_sigrestart(int sig) { pthread_descr self = thread_self(); +#else +static void pthread_handle_sigrestart(int sig, struct sigcontext ctx) +{ + pthread_descr self; + asm volatile ("movw %w0,%%gs" : : "r" (ctx.gs)); + self = thread_self(); +#endif if (self == &__pthread_manager_thread) { __pthread_manager_sighandler(sig); } else { - self->p_signal = sig; - if (self->p_signal_jmp != NULL) siglongjmp(*self->p_signal_jmp, 1); + THREAD_SETMEM(self, p_signal, sig); + if (THREAD_GETMEM(self, p_signal_jmp) != NULL) + siglongjmp(*THREAD_GETMEM(self, p_signal_jmp), 1); } } @@ -451,10 +489,19 @@ static void pthread_handle_sigrestart(int sig) know what it is specifically done for. In the current implementation, the thread manager simply discards it. */ +#ifndef __i386__ static void pthread_handle_sigcancel(int sig) { pthread_descr self = thread_self(); sigjmp_buf * jmpbuf; +#else +static void pthread_handle_sigcancel(int sig, struct sigcontext ctx) +{ + pthread_descr self; + sigjmp_buf * jmpbuf; + asm volatile ("movw %w0,%%gs" : : "r" (ctx.gs)); + self = thread_self(); +#endif if (self == &__pthread_manager_thread) return; @@ -465,12 +512,13 @@ static void pthread_handle_sigcancel(int sig) waitpid(__pthread_manager_thread.p_pid, NULL, __WCLONE); _exit(__pthread_exit_code); } - if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) { - if (self->p_canceltype == PTHREAD_CANCEL_ASYNCHRONOUS) + if (THREAD_GETMEM(self, p_canceled) + && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) { + if (THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS) pthread_exit(PTHREAD_CANCELED); - jmpbuf = self->p_cancel_jmp; + jmpbuf = THREAD_GETMEM(self, p_cancel_jmp); if (jmpbuf != NULL) { - self->p_cancel_jmp = NULL; + THREAD_SETMEM(self, p_cancel_jmp, NULL); siglongjmp(*jmpbuf, 1); } } @@ -496,14 +544,14 @@ void __pthread_reset_main_thread() __pthread_manager_request = __pthread_manager_reader = -1; } /* Update the pid of the main thread */ - self->p_pid = __getpid(); + THREAD_SETMEM(self, p_pid, __getpid()); /* Make the forked thread the main thread */ __pthread_main_thread = self; - self->p_nextlive = self; - self->p_prevlive = self; + THREAD_SETMEM(self, p_nextlive, self); + THREAD_SETMEM(self, p_prevlive, self); /* Now this thread modifies the global variables. */ - self->p_errnop = &_errno; - self->p_h_errnop = &_h_errno; + THREAD_SETMEM(self, p_errnop, &_errno); + THREAD_SETMEM(self, p_h_errnop, &_h_errno); } /* Process-wide exec() request */ diff --git a/linuxthreads/ptlongjmp.c b/linuxthreads/ptlongjmp.c index 580ae93f88..7e4314ec2d 100644 --- a/linuxthreads/ptlongjmp.c +++ b/linuxthreads/ptlongjmp.c @@ -32,13 +32,14 @@ static void pthread_cleanup_upto(__jmp_buf target) pthread_descr self = thread_self(); struct _pthread_cleanup_buffer * c; - for (c = self->p_cleanup; + for (c = THREAD_GETMEM(self, p_cleanup); c != NULL && _JMPBUF_UNWINDS(target, c); c = c->prev) c->routine(c->arg); - self->p_cleanup = c; - if (self->p_in_sighandler && _JMPBUF_UNWINDS(target, self->p_in_sighandler)) - self->p_in_sighandler = NULL; + THREAD_SETMEM(self, p_cleanup, c); + if (THREAD_GETMEM(self, p_in_sighandler) + && _JMPBUF_UNWINDS(target, THREAD_GETMEM(self, p_in_sighandler))) + THREAD_SETMEM(self, p_in_sighandler, NULL); } void siglongjmp(sigjmp_buf env, int val) diff --git a/linuxthreads/semaphore.c b/linuxthreads/semaphore.c index 6f79dc0138..af5f115a16 100644 --- a/linuxthreads/semaphore.c +++ b/linuxthreads/semaphore.c @@ -54,7 +54,8 @@ int sem_wait(sem_t * sem) __pthread_unlock((struct _pthread_fastlock *) &sem->sem_lock); suspend_with_cancellation(self); /* This is a cancellation point */ - if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) { + if (THREAD_GETMEM(self, p_canceled) + && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) { /* Remove ourselves from the waiting list if we're still on it */ __pthread_lock((struct _pthread_fastlock *) &sem->sem_lock); remove_from_queue(&sem->sem_waiting, self); @@ -86,7 +87,7 @@ int sem_post(sem_t * sem) pthread_descr th; struct pthread_request request; - if (self->p_in_sighandler == NULL) { + if (THREAD_GETMEM(self, p_in_sighandler) == NULL) { __pthread_lock((struct _pthread_fastlock *) &sem->sem_lock); if (sem->sem_waiting == NULL) { if (sem->sem_value >= SEM_VALUE_MAX) { diff --git a/linuxthreads/signals.c b/linuxthreads/signals.c index 392b5ea5a9..a6674bfc0d 100644 --- a/linuxthreads/signals.c +++ b/linuxthreads/signals.c @@ -76,17 +76,19 @@ static void pthread_sighandler(int signo) char * in_sighandler; /* If we're in a sigwait operation, just record the signal received and return without calling the user's handler */ - if (self->p_sigwaiting) { - self->p_sigwaiting = 0; - self->p_signal = signo; + if (THREAD_GETMEM(self, p_sigwaiting)) { + THREAD_SETMEM(self, p_sigwaiting, 0); + THREAD_SETMEM(self, p_signal, signo); return; } /* Record that we're in a signal handler and call the user's handler function */ - in_sighandler = self->p_in_sighandler; - if (in_sighandler == NULL) self->p_in_sighandler = CURRENT_STACK_FRAME; + in_sighandler = THREAD_GETMEM(self, p_in_sighandler); + if (in_sighandler == NULL) + THREAD_SETMEM(self, p_in_sighandler, CURRENT_STACK_FRAME); sighandler[signo](signo); - if (in_sighandler == NULL) self->p_in_sighandler = NULL; + if (in_sighandler == NULL) + THREAD_SETMEM(self, p_in_sighandler, NULL); } int sigaction(int sig, const struct sigaction * act, @@ -131,21 +133,22 @@ int sigwait(const sigset_t * set, int * sig) } /* Test for cancellation */ if (sigsetjmp(jmpbuf, 1) == 0) { - self->p_cancel_jmp = &jmpbuf; - if (! (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE)) { + THREAD_SETMEM(self, p_cancel_jmp, &jmpbuf); + if (! (THREAD_GETMEM(self, p_canceled) + && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) { /* Reset the signal count */ - self->p_signal = 0; + THREAD_SETMEM(self, p_signal, 0); /* Say we're in sigwait */ - self->p_sigwaiting = 1; + THREAD_SETMEM(self, p_sigwaiting, 1); /* Unblock the signals and wait for them */ sigsuspend(&mask); } } - self->p_cancel_jmp = NULL; + THREAD_SETMEM(self, p_cancel_jmp, NULL); /* The signals are now reblocked. Check for cancellation */ pthread_testcancel(); /* We should have self->p_signal != 0 and equal to the signal received */ - *sig = self->p_signal; + *sig = THREAD_GETMEM(self, p_signal); return 0; } diff --git a/linuxthreads/specific.c b/linuxthreads/specific.c index 12990f454c..4ebbad7f5f 100644 --- a/linuxthreads/specific.c +++ b/linuxthreads/specific.c @@ -99,13 +99,13 @@ int __pthread_setspecific(pthread_key_t key, const void * pointer) return EINVAL; idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE; idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE; - if (self->p_specific[idx1st] == NULL) { - self->p_specific[idx1st] = - calloc(PTHREAD_KEY_2NDLEVEL_SIZE, sizeof (void *)); - if (self->p_specific[idx1st] == NULL) + if (THREAD_GETMEM(self, p_specific[idx1st]) == NULL) { + THREAD_SETMEM(self, p_specific[idx1st], + calloc(PTHREAD_KEY_2NDLEVEL_SIZE, sizeof (void *))); + if (THREAD_GETMEM(self, p_specific[idx1st]) == NULL) return ENOMEM; } - self->p_specific[idx1st][idx2nd] = (void *) pointer; + THREAD_GETMEM(self, p_specific[idx1st])[idx2nd] = (void *) pointer; return 0; } weak_alias (__pthread_setspecific, pthread_setspecific) @@ -121,9 +121,10 @@ void * __pthread_getspecific(pthread_key_t key) return NULL; idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE; idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE; - if (self->p_specific[idx1st] == NULL || !pthread_keys[key].in_use) + if (THREAD_GETMEM(self, p_specific[idx1st]) == NULL + || !pthread_keys[key].in_use) return NULL; - return self->p_specific[idx1st][idx2nd]; + return THREAD_GETMEM(self, p_specific[idx1st])[idx2nd]; } weak_alias (__pthread_getspecific, pthread_getspecific) @@ -141,19 +142,20 @@ void __pthread_destroy_specifics() round++) { found_nonzero = 0; for (i = 0; i < PTHREAD_KEY_1STLEVEL_SIZE; i++) - if (self->p_specific[i] != NULL) + if (THREAD_GETMEM(self, p_specific[i]) != NULL) for (j = 0; j < PTHREAD_KEY_2NDLEVEL_SIZE; j++) { destr = pthread_keys[i * PTHREAD_KEY_2NDLEVEL_SIZE + j].destr; - data = self->p_specific[i][j]; + data = THREAD_GETMEM(self, p_specific[i])[j]; if (destr != NULL && data != NULL) { - self->p_specific[i][j] = NULL; + THREAD_GETMEM(self, p_specific[i])[j] = NULL; destr(data); found_nonzero = 1; } } } for (i = 0; i < PTHREAD_KEY_1STLEVEL_SIZE; i++) { - if (self->p_specific[i] != NULL) free(self->p_specific[i]); + if (THREAD_GETMEM(self, p_specific[i]) != NULL) + free(THREAD_GETMEM(self, p_specific[i])); } } @@ -163,7 +165,7 @@ int __libc_internal_tsd_set(enum __libc_tsd_key_t key, const void * pointer) { pthread_descr self = thread_self(); - self->p_libc_specific[key] = (void *) pointer; + THREAD_SETMEM(self, p_libc_specific[key], (void *) pointer); return 0; } @@ -171,5 +173,5 @@ void * __libc_internal_tsd_get(enum __libc_tsd_key_t key) { pthread_descr self = thread_self(); - return self->p_libc_specific[key]; + return THREAD_GETMEM(self, p_libc_specific[key]); } diff --git a/linuxthreads/spinlock.c b/linuxthreads/spinlock.c index 8a8d3bfb84..15faec0e7d 100644 --- a/linuxthreads/spinlock.c +++ b/linuxthreads/spinlock.c @@ -50,7 +50,7 @@ void __pthread_lock(struct _pthread_fastlock * lock) newstatus = (long) self; } if (self != NULL) - self->p_nextwaiting = (pthread_descr) oldstatus; + THREAD_SETMEM(self, p_nextwaiting, (pthread_descr) oldstatus); } while(! compare_and_swap(&lock->status, oldstatus, newstatus, &lock->spinlock)); if (oldstatus != 0) suspend(self); diff --git a/linuxthreads/sysdeps/alpha/pt-machine.h b/linuxthreads/sysdeps/alpha/pt-machine.h index a0c7cc77e2..41b37daf8e 100644 --- a/linuxthreads/sysdeps/alpha/pt-machine.h +++ b/linuxthreads/sysdeps/alpha/pt-machine.h @@ -1,6 +1,6 @@ /* Machine-dependent pthreads configuration and inline functions. Alpha version. - Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Richard Henderson . @@ -70,7 +70,7 @@ register char *stack_pointer __asm__("$30"); }) /* Initialize the thread-unique value. */ -#define INIT_THREAD_SELF(descr) \ +#define INIT_THREAD_SELF(descr, nr) \ { \ register pthread_descr __self __asm__("$16") = (descr); \ __asm__ __volatile__ ("call_pal %1" : : "r"(__self), "i"(PAL_wruniq)); \ diff --git a/linuxthreads/sysdeps/i386/i686/pt-machine.h b/linuxthreads/sysdeps/i386/i686/pt-machine.h index bb0f0bc8e1..a4b3a63f1c 100644 --- a/linuxthreads/sysdeps/i386/i686/pt-machine.h +++ b/linuxthreads/sysdeps/i386/i686/pt-machine.h @@ -70,3 +70,7 @@ set_eflags (int newflags) { __asm__ __volatile__ ("pushl %0; popfl" : : "r" (newflags) : "cc"); } + + +/* Use the LDT implementation only if the kernel is fixed. */ +//#include "../useldt.h" diff --git a/linuxthreads/sysdeps/i386/useldt.h b/linuxthreads/sysdeps/i386/useldt.h new file mode 100644 index 0000000000..2fdc0ce767 --- /dev/null +++ b/linuxthreads/sysdeps/i386/useldt.h @@ -0,0 +1,124 @@ +/* Special definitions for ix86 machine using segment register based + thread descriptor. + Copyright (C) 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include /* For offsetof. */ + + +/* We don't want to include the kernel header. So duplicate the + information. */ + +/* Structure passed on `modify_ldt' call. */ +struct modify_ldt_ldt_s +{ + unsigned int entry_number; + unsigned long int base_addr; + unsigned int limit; + unsigned int seg_32bit:1; + unsigned int contents:2; + unsigned int read_exec_only:1; + unsigned int limit_in_pages:1; + unsigned int seg_not_present:1; + unsigned int useable:1; + unsigned int empty:25; +}; + +/* System call to set LDT entry. */ +extern int __modify_ldt (int, struct modify_ldt_ldt_s *, size_t); + + +/* Return the thread descriptor for the current thread. + + The contained asm must *not* be marked volatile since otherwise + assignments like + pthread_descr self = thread_self(); + do not get optimized away. */ +#define THREAD_SELF \ +({ \ + register pthread_descr __self; \ + __asm__ ("movl %%gs:%c1,%0" : "=r" (__self) \ + : "i" (offsetof (struct _pthread_descr_struct, p_self))); \ + __self; \ +}) + +/* Initialize the thread-unique value. */ +#define INIT_THREAD_SELF(descr, nr) \ +{ \ + struct modify_ldt_ldt_s ldt_entry = \ + { nr, (unsigned long int) descr, sizeof (*descr), 1, 0, 0, 0, 0, 1, 0 }; \ + if (__modify_ldt (1, &ldt_entry, sizeof (ldt_entry)) != 0) \ + abort (); \ + __asm__ __volatile__ ("movw %w0, %%gs" : : "r" (nr * 8 + 7)); \ +} + +/* Free resources associated with thread descriptor. */ +#define FREE_THREAD_SELF(descr, nr) \ +{ \ + struct modify_ldt_ldt_s ldt_entry = \ + { nr, 0, 0, 0, 0, 1, 0, 1, 0, 0 }; \ + __asm__ __volatile__ ("movw %w0,%%gs" : : "r" (0)); \ + __modify_ldt (1, &ldt_entry, sizeof (ldt_entry)); \ +} + +/* Read member of the thread descriptor directly. */ +#define THREAD_GETMEM(descr, member) \ +({ \ + __typeof__ (descr->member) __value; \ + if (sizeof (__value) == 1) \ + __asm__ __volatile__ ("movb %%gs:%c1,%b0" \ + : "=r" (__value) \ + : "0" (0), \ + "i" (offsetof (struct _pthread_descr_struct, \ + member))); \ + else \ + { \ + if (sizeof (__value) != 4) \ + /* There should not be any value with a size other than 1 or 4. */ \ + abort (); \ + \ + __asm__ __volatile__ ("movl %%gs:%c1,%0" \ + : "=r" (__value) \ + : "i" (offsetof (struct _pthread_descr_struct, \ + member))); \ + } \ + __value; \ +}) + +/* Set member of the thread descriptor directly. */ +#define THREAD_SETMEM(descr, member, value) \ +({ \ + __typeof__ (descr->member) __value = (value); \ + if (sizeof (__value) == 1) \ + __asm__ __volatile__ ("movb %0,%%gs:%c1" : \ + : "r" (__value), \ + "i" (offsetof (struct _pthread_descr_struct, \ + member))); \ + else \ + { \ + if (sizeof (__value) != 4) \ + /* There should not be any value with a size other than 1 or 4. */ \ + abort (); \ + \ + __asm__ __volatile__ ("movl %0,%%gs:%c1" : \ + : "r" (__value), \ + "i" (offsetof (struct _pthread_descr_struct, \ + member))); \ + } \ +}) diff --git a/linuxthreads/sysdeps/sparc/sparc32/pt-machine.h b/linuxthreads/sysdeps/sparc/sparc32/pt-machine.h index 13f78e319a..7eea8d400c 100644 --- a/linuxthreads/sysdeps/sparc/sparc32/pt-machine.h +++ b/linuxthreads/sysdeps/sparc/sparc32/pt-machine.h @@ -1,6 +1,6 @@ /* Machine-dependent pthreads configuration and inline functions. sparc version. - Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Richard Henderson . @@ -53,3 +53,7 @@ register struct _pthread_descr_struct *__thread_self __asm__("%g6"); /* Initialize the thread-unique value. */ #define INIT_THREAD_SELF(descr) (__thread_self = (descr)) + +/* Access to data in the thread descriptor is easy. */ +#define THREAD_GETMEM(descr, member) __thread_self->member +#define THREAD_SETMEM(descr, member, value) __thread_self->member = (value) diff --git a/linuxthreads/sysdeps/sparc/sparc64/pt-machine.h b/linuxthreads/sysdeps/sparc/sparc64/pt-machine.h index 5424860786..e94e1a5fb2 100644 --- a/linuxthreads/sysdeps/sparc/sparc64/pt-machine.h +++ b/linuxthreads/sysdeps/sparc/sparc64/pt-machine.h @@ -1,6 +1,6 @@ /* Machine-dependent pthreads configuration and inline functions. Sparc v9 version. - Copyright (C) 1997 Free Software Foundation, Inc. + Copyright (C) 1997, 1998 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Richard Henderson . @@ -65,3 +65,7 @@ __compare_and_swap (long int *p, long int oldval, long int newval) return readval == newval; } + +/* Access to data in the thread descriptor is easy. */ +#define THREAD_GETMEM(descr, member) __thread_self->member +#define THREAD_SETMEM(descr, member, value) __thread_self->member = (value) -- cgit 1.4.1