1998-08-26 15:46  Ulrich Drepper  <drepper@cygnus.com>

	* 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.
This commit is contained in:
Ulrich Drepper 1998-08-26 16:00:46 +00:00
parent 08cac4ac19
commit 00a2f9aa41
19 changed files with 369 additions and 113 deletions

View File

@ -59,7 +59,7 @@ _IO_getline_info (fp, buf, n, delim, extract_delim, eof)
char *ptr = buf;
if (eof != NULL)
*eof = 0;
while (n != 0);
while (n != 0)
{
_IO_ssize_t len = fp->_IO_read_end - fp->_IO_read_ptr;
if (len <= 0)

View File

@ -1,3 +1,43 @@
1998-08-26 15:46 Ulrich Drepper <drepper@cygnus.com>
* 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 <geoffk@ozemail.com.au>
* spinlock.c (__pthread_lock): Reset p_nextwaiting to NULL if it

View File

@ -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

View File

@ -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);

View File

@ -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);
}

View File

@ -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. */

View File

@ -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);
}

View File

@ -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 */

View File

@ -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 */

View File

@ -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)

View File

@ -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) {

View File

@ -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;
}

View File

@ -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]);
}

View File

@ -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);

View File

@ -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 <rth@tamu.edu>.
@ -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)); \

View File

@ -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"

View File

@ -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 <drepper@cygnus.com>.
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 <stddef.h> /* 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))); \
} \
})

View File

@ -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 <rth@tamu.edu>.
@ -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)

View File

@ -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 <rth@tamu.edu>.
@ -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)