aboutsummaryrefslogtreecommitdiff
path: root/linuxthreads
diff options
context:
space:
mode:
Diffstat (limited to 'linuxthreads')
-rw-r--r--linuxthreads/ChangeLog29
-rw-r--r--linuxthreads/attr.c8
-rw-r--r--linuxthreads/cancel.c6
-rw-r--r--linuxthreads/condvar.c79
-rw-r--r--linuxthreads/internals.h28
-rw-r--r--linuxthreads/join.c28
-rw-r--r--linuxthreads/manager.c79
-rw-r--r--linuxthreads/mutex.c122
-rw-r--r--linuxthreads/pthread.c89
-rw-r--r--linuxthreads/ptlongjmp.c2
-rw-r--r--linuxthreads/queue.h57
-rw-r--r--linuxthreads/rwlock.c47
-rw-r--r--linuxthreads/semaphore.c236
-rw-r--r--linuxthreads/semaphore.h7
-rw-r--r--linuxthreads/signals.c89
-rw-r--r--linuxthreads/spinlock.c123
-rw-r--r--linuxthreads/spinlock.h53
-rw-r--r--linuxthreads/sysdeps/i386/pt-machine.h6
-rw-r--r--linuxthreads/sysdeps/pthread/pthread.h38
-rw-r--r--linuxthreads/sysdeps/unix/sysv/linux/bits/posix_opt.h8
20 files changed, 626 insertions, 508 deletions
diff --git a/linuxthreads/ChangeLog b/linuxthreads/ChangeLog
index 69426bfb7c..882aa41d45 100644
--- a/linuxthreads/ChangeLog
+++ b/linuxthreads/ChangeLog
@@ -1,3 +1,32 @@
+1998-06-25 19:27 Ulrich Drepper <drepper@cygnus.com>
+
+ * attr.c: Finish user stack support. Change locking code to be safe
+ in situations with different priorities.
+ * cancel.c: Likewise.
+ * condvar.c: Likewise.
+ * internals.h: Likewise.
+ * join.c: Likewise.
+ * manager.c: Likewise.
+ * mutex.c: Likewise.
+ * pthread.c: Likewise.
+ * ptlongjmp.c: Likewise.
+ * queue.h: Likewise.
+ * rwlock.c: Likewise.
+ * semaphore.c: Likewise.
+ * semaphore.h: Likewise.
+ * signals.c: Likewise.
+ * spinlock.c: Likewise.
+ * spinlock.h: Likewise.
+ Patches by Xavier leroy.
+
+1998-06-25 Ulrich Drepper <drepper@cygnus.com>
+
+ * sysdeps/pthread/pthread.h: Make [sg]et_stacksize and
+ [sg]et_stackaddr prototypes always available.
+
+ * sysdeps/unix/sysv/linux/bits/posix_opt.h: Define
+ _POSIX_THREAD_ATTR_STACKSIZE and _POSIX_THREAD_ATTR_STACKADDR.
+
1998-06-24 Ulrich Drepper <drepper@cygnus.com>
* manager.c (pthread_free): Undo patch from 980430.
diff --git a/linuxthreads/attr.c b/linuxthreads/attr.c
index 027f69c997..d1f605810f 100644
--- a/linuxthreads/attr.c
+++ b/linuxthreads/attr.c
@@ -19,7 +19,6 @@
#include "pthread.h"
#include "internals.h"
-
int __pthread_attr_init_2_1(pthread_attr_t *attr)
{
size_t ps = __getpagesize ();
@@ -185,11 +184,8 @@ weak_alias (__pthread_attr_getstackaddr, pthread_attr_getstackaddr)
int __pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
{
- size_t ps = __getpagesize ();
-
- /* We don't accept value smaller than PTHREAD_STACK_MIN or bigger than
- 2MB - pagesize. */
- if (stacksize < PTHREAD_STACK_MIN || stacksize > STACK_SIZE - ps)
+ /* We don't accept value smaller than PTHREAD_STACK_MIN. */
+ if (stacksize < PTHREAD_STACK_MIN)
return EINVAL;
attr->stacksize = stacksize;
diff --git a/linuxthreads/cancel.c b/linuxthreads/cancel.c
index a6a0ecaa5a..cd2bbace12 100644
--- a/linuxthreads/cancel.c
+++ b/linuxthreads/cancel.c
@@ -53,14 +53,14 @@ int pthread_cancel(pthread_t thread)
pthread_handle handle = thread_handle(thread);
int pid;
- acquire(&handle->h_spinlock);
+ __pthread_lock(&handle->h_lock);
if (invalid_handle(handle, thread)) {
- release(&handle->h_spinlock);
+ __pthread_unlock(&handle->h_lock);
return ESRCH;
}
handle->h_descr->p_canceled = 1;
pid = handle->h_descr->p_pid;
- release(&handle->h_spinlock);
+ __pthread_unlock(&handle->h_lock);
kill(pid, PTHREAD_SIG_CANCEL);
return 0;
}
diff --git a/linuxthreads/condvar.c b/linuxthreads/condvar.c
index 6807522edc..91067d2d17 100644
--- a/linuxthreads/condvar.c
+++ b/linuxthreads/condvar.c
@@ -25,42 +25,36 @@
#include "queue.h"
#include "restart.h"
-static void remove_from_queue(pthread_queue * q, pthread_descr th);
-
int pthread_cond_init(pthread_cond_t *cond,
const pthread_condattr_t *cond_attr)
{
- cond->c_spinlock = 0;
- queue_init(&cond->c_waiting);
+ __pthread_init_lock(&cond->c_lock);
+ cond->c_waiting = NULL;
return 0;
}
int pthread_cond_destroy(pthread_cond_t *cond)
{
- pthread_descr head;
-
- acquire(&cond->c_spinlock);
- head = cond->c_waiting.head;
- release(&cond->c_spinlock);
- if (head != NULL) return EBUSY;
+ if (cond->c_waiting != NULL) return EBUSY;
return 0;
}
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
{
volatile pthread_descr self = thread_self();
- acquire(&cond->c_spinlock);
+
+ __pthread_lock(&cond->c_lock);
enqueue(&cond->c_waiting, self);
- release(&cond->c_spinlock);
+ __pthread_unlock(&cond->c_lock);
pthread_mutex_unlock(mutex);
suspend_with_cancellation(self);
pthread_mutex_lock(mutex);
/* This is a cancellation point */
if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) {
/* Remove ourselves from the waiting queue if we're still on it */
- acquire(&cond->c_spinlock);
+ __pthread_lock(&cond->c_lock);
remove_from_queue(&cond->c_waiting, self);
- release(&cond->c_spinlock);
+ __pthread_unlock(&cond->c_lock);
pthread_exit(PTHREAD_CANCELED);
}
return 0;
@@ -77,15 +71,14 @@ pthread_cond_timedwait_relative(pthread_cond_t *cond,
sigjmp_buf jmpbuf;
/* Wait on the condition */
- acquire(&cond->c_spinlock);
+ __pthread_lock(&cond->c_lock);
enqueue(&cond->c_waiting, self);
- release(&cond->c_spinlock);
+ __pthread_unlock(&cond->c_lock);
pthread_mutex_unlock(mutex);
- /* Set up a longjmp handler for the restart signal */
- /* No need to save the signal mask, since PTHREAD_SIG_RESTART will be
- blocked when doing the siglongjmp, and we'll just leave it blocked. */
- if (sigsetjmp(jmpbuf, 0) == 0) {
+ /* 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;
/* Check for cancellation */
if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) {
@@ -104,28 +97,28 @@ pthread_cond_timedwait_relative(pthread_cond_t *cond,
retsleep = -1;
}
self->p_signal_jmp = NULL;
+ 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) */
- /* Re-acquire the spinlock */
- acquire(&cond->c_spinlock);
/* This is a cancellation point */
if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) {
+ __pthread_lock(&cond->c_lock);
remove_from_queue(&cond->c_waiting, self);
- release(&cond->c_spinlock);
+ __pthread_unlock(&cond->c_lock);
pthread_mutex_lock(mutex);
pthread_exit(PTHREAD_CANCELED);
}
/* If not signaled: also remove ourselves and return an error code */
if (self->p_signal == 0) {
+ __pthread_lock(&cond->c_lock);
remove_from_queue(&cond->c_waiting, self);
- release(&cond->c_spinlock);
+ __pthread_unlock(&cond->c_lock);
pthread_mutex_lock(mutex);
return retsleep == 0 ? ETIMEDOUT : EINTR;
}
/* Otherwise, return normally */
- release(&cond->c_spinlock);
pthread_mutex_lock(mutex);
return 0;
}
@@ -151,23 +144,22 @@ int pthread_cond_signal(pthread_cond_t *cond)
{
pthread_descr th;
- acquire(&cond->c_spinlock);
+ __pthread_lock(&cond->c_lock);
th = dequeue(&cond->c_waiting);
- release(&cond->c_spinlock);
+ __pthread_unlock(&cond->c_lock);
if (th != NULL) restart(th);
return 0;
}
int pthread_cond_broadcast(pthread_cond_t *cond)
{
- pthread_queue tosignal;
- pthread_descr th;
+ pthread_descr tosignal, th;
- acquire(&cond->c_spinlock);
+ __pthread_lock(&cond->c_lock);
/* Copy the current state of the waiting queue and empty it */
tosignal = cond->c_waiting;
- queue_init(&cond->c_waiting);
- release(&cond->c_spinlock);
+ cond->c_waiting = NULL;
+ __pthread_unlock(&cond->c_lock);
/* Now signal each process in the queue */
while ((th = dequeue(&tosignal)) != NULL) restart(th);
return 0;
@@ -182,26 +174,3 @@ int pthread_condattr_destroy(pthread_condattr_t *attr)
{
return 0;
}
-
-/* Auxiliary function on queues */
-
-static void remove_from_queue(pthread_queue * q, pthread_descr th)
-{
- pthread_descr t;
-
- if (q->head == NULL) return;
- if (q->head == th) {
- q->head = th->p_nextwaiting;
- if (q->head == NULL) q->tail = NULL;
- th->p_nextwaiting = NULL;
- return;
- }
- for (t = q->head; t->p_nextwaiting != NULL; t = t->p_nextwaiting) {
- if (t->p_nextwaiting == th) {
- t->p_nextwaiting = th->p_nextwaiting;
- if (th->p_nextwaiting == NULL) q->tail = t;
- th->p_nextwaiting = NULL;
- return;
- }
- }
-}
diff --git a/linuxthreads/internals.h b/linuxthreads/internals.h
index ab6b66a857..0a01b61ede 100644
--- a/linuxthreads/internals.h
+++ b/linuxthreads/internals.h
@@ -63,7 +63,7 @@ struct _pthread_descr_struct {
pthread_t p_tid; /* Thread identifier */
int p_pid; /* PID of Unix process */
int p_priority; /* Thread priority (== 0 if not realtime) */
- int * p_spinlock; /* Spinlock for synchronized accesses */
+ struct _pthread_fastlock * p_lock; /* Spinlock for synchronized accesses */
int p_signal; /* last signal received */
sigjmp_buf * p_signal_jmp; /* where to siglongjmp on a signal or NULL */
sigjmp_buf * p_cancel_jmp; /* where to siglongjmp on a cancel or NULL */
@@ -81,6 +81,8 @@ struct _pthread_descr_struct {
int p_errno; /* error returned by last system call */
int * p_h_errnop; /* pointer to used h_errno variable */
int p_h_errno; /* error returned by last netdb function */
+ char * p_in_sighandler; /* stack address of sighandler, or NULL */
+ char p_sigwaiting; /* true if a sigwait() is in progress */
struct pthread_start_args p_start_args; /* arguments for thread creation */
void ** p_specific[PTHREAD_KEY_1STLEVEL_SIZE]; /* thread-specific data */
void * p_libc_specific[_LIBC_TSD_KEY_N]; /* thread-specific data for libc */
@@ -94,8 +96,9 @@ struct _pthread_descr_struct {
typedef struct pthread_handle_struct * pthread_handle;
struct pthread_handle_struct {
- int h_spinlock; /* Spinlock for sychronized access */
+ struct _pthread_fastlock h_lock; /* Fast lock for sychronized access */
pthread_descr h_descr; /* Thread descriptor or NULL if invalid */
+ char * h_bottom; /* Lowest address in the stack thread */
};
/* The type of messages sent to the thread manager thread */
@@ -103,7 +106,8 @@ struct pthread_handle_struct {
struct pthread_request {
pthread_descr req_thread; /* Thread doing the request */
enum { /* Request kind */
- REQ_CREATE, REQ_FREE, REQ_PROCESS_EXIT, REQ_MAIN_THREAD_EXIT
+ REQ_CREATE, REQ_FREE, REQ_PROCESS_EXIT, REQ_MAIN_THREAD_EXIT,
+ REQ_POST, REQ_DEBUG
} req_kind;
union { /* Arguments for request */
struct { /* For REQ_CREATE: */
@@ -118,6 +122,7 @@ struct pthread_request {
struct { /* For REQ_PROCESS_EXIT: */
int code; /* exit status */
} exit;
+ void * post; /* For REQ_POST: the semaphore */
} req_args;
};
@@ -160,6 +165,11 @@ extern pthread_descr __pthread_main_thread;
extern char *__pthread_initial_thread_bos;
+/* Indicate whether at least one thread has a user-defined stack (if 1),
+ or all threads have stacks supplied by LinuxThreads (if 0). */
+
+extern int __pthread_nonstandard_stacks;
+
/* File descriptor for sending requests to the thread manager.
Initially -1, meaning that pthread_initialize must be called. */
@@ -178,6 +188,10 @@ extern char *__pthread_manager_thread_tos;
extern int __pthread_exit_requested, __pthread_exit_code;
+/* Set to 1 by gdb if we're debugging */
+
+extern volatile int __pthread_threads_debug;
+
/* Return the handle corresponding to a thread id */
static inline pthread_handle thread_handle(pthread_t id)
@@ -233,6 +247,8 @@ static inline int invalid_handle(pthread_handle h, pthread_t id)
/* Recover thread descriptor for the current thread */
+extern pthread_descr __pthread_find_self (void) __attribute__ ((const));
+
static inline pthread_descr thread_self (void) __attribute__ ((const));
static inline pthread_descr thread_self (void)
{
@@ -245,6 +261,8 @@ static inline pthread_descr thread_self (void)
else if (sp >= __pthread_manager_thread_bos
&& sp < __pthread_manager_thread_tos)
return &__pthread_manager_thread;
+ else if (__pthread_nonstandard_stacks)
+ return __pthread_find_self();
else
return (pthread_descr)(((unsigned long)sp | (STACK_SIZE-1))+1) - 1;
#endif
@@ -282,8 +300,8 @@ static inline pthread_descr thread_self (void)
void __pthread_destroy_specifics(void);
void __pthread_perform_cleanup(void);
-void __pthread_sighandler(int sig);
-void __pthread_message(char * fmt, long arg, ...);
+int __pthread_initialize_manager(void);
+void __pthread_message(char * fmt, ...);
int __pthread_manager(void *reqfd);
void __pthread_manager_sighandler(int sig);
void __pthread_reset_main_thread(void);
diff --git a/linuxthreads/join.c b/linuxthreads/join.c
index 2bdc189631..c59de6985a 100644
--- a/linuxthreads/join.c
+++ b/linuxthreads/join.c
@@ -35,13 +35,13 @@ void pthread_exit(void * retval)
__pthread_perform_cleanup();
__pthread_destroy_specifics();
/* Store return value */
- acquire(self->p_spinlock);
+ __pthread_lock(self->p_lock);
self->p_retval = retval;
/* Say that we've terminated */
self->p_terminated = 1;
/* See if someone is joining on us */
joining = self->p_joining;
- release(self->p_spinlock);
+ __pthread_unlock(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.
@@ -65,36 +65,36 @@ int pthread_join(pthread_t thread_id, void ** thread_return)
pthread_handle handle = thread_handle(thread_id);
pthread_descr th;
- acquire(&handle->h_spinlock);
+ __pthread_lock(&handle->h_lock);
if (invalid_handle(handle, thread_id)) {
- release(&handle->h_spinlock);
+ __pthread_unlock(&handle->h_lock);
return ESRCH;
}
th = handle->h_descr;
if (th == self) {
- release(&handle->h_spinlock);
+ __pthread_unlock(&handle->h_lock);
return EDEADLK;
}
/* If detached or already joined, error */
if (th->p_detached || th->p_joining != NULL) {
- release(&handle->h_spinlock);
+ __pthread_unlock(&handle->h_lock);
return EINVAL;
}
/* If not terminated yet, suspend ourselves. */
if (! th->p_terminated) {
th->p_joining = self;
- release(&handle->h_spinlock);
+ __pthread_unlock(&handle->h_lock);
suspend_with_cancellation(self);
/* This is a cancellation point */
if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) {
th->p_joining = NULL;
pthread_exit(PTHREAD_CANCELED);
}
- acquire(&handle->h_spinlock);
+ __pthread_lock(&handle->h_lock);
}
/* Get return value */
if (thread_return != NULL) *thread_return = th->p_retval;
- release(&handle->h_spinlock);
+ __pthread_unlock(&handle->h_lock);
/* Send notification to thread manager */
if (__pthread_manager_request >= 0) {
request.req_thread = self;
@@ -113,26 +113,26 @@ int pthread_detach(pthread_t thread_id)
pthread_handle handle = thread_handle(thread_id);
pthread_descr th;
- acquire(&handle->h_spinlock);
+ __pthread_lock(&handle->h_lock);
if (invalid_handle(handle, thread_id)) {
- release(&handle->h_spinlock);
+ __pthread_unlock(&handle->h_lock);
return ESRCH;
}
th = handle->h_descr;
/* If already detached, error */
if (th->p_detached) {
- release(&handle->h_spinlock);
+ __pthread_unlock(&handle->h_lock);
return EINVAL;
}
/* If already joining, don't do anything. */
if (th->p_joining != NULL) {
- release(&handle->h_spinlock);
+ __pthread_unlock(&handle->h_lock);
return 0;
}
/* Mark as detached */
th->p_detached = 1;
terminated = th->p_terminated;
- release(&handle->h_spinlock);
+ __pthread_unlock(&handle->h_lock);
/* If already terminated, notify thread manager to reclaim resources */
if (terminated && __pthread_manager_request >= 0) {
request.req_thread = thread_self();
diff --git a/linuxthreads/manager.c b/linuxthreads/manager.c
index ac78d6e4ce..36c592197e 100644
--- a/linuxthreads/manager.c
+++ b/linuxthreads/manager.c
@@ -31,15 +31,22 @@
#include "internals.h"
#include "spinlock.h"
#include "restart.h"
+#include "semaphore.h"
/* Array of active threads. Entry 0 is reserved for the initial thread. */
-
struct pthread_handle_struct __pthread_handles[PTHREAD_THREADS_MAX] =
-{ { 0, &__pthread_initial_thread, 0}, /* All NULLs */ };
+{ { LOCK_INITIALIZER, &__pthread_initial_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;
+int __pthread_nonstandard_stacks = 0;
+
+/* Number of active entries in __pthread_handles (used by gdb) */
+volatile int __pthread_handles_num = 1;
+
+/* Whether to use debugger additional actions for thread creation
+ (set to 1 by gdb) */
+volatile int __pthread_threads_debug = 0;
/* Mapping from stack segment to thread descriptor. */
/* Stack segment numbers are also indices into the __pthread_handles array. */
@@ -93,12 +100,18 @@ int __pthread_manager(void *arg)
/* 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;
- /* Block all signals except PTHREAD_SIG_RESTART */
+ /* Block all signals except PTHREAD_SIG_RESTART, PTHREAD_SIG_CANCEL
+ and SIGTRAP */
sigfillset(&mask);
sigdelset(&mask, PTHREAD_SIG_RESTART);
+ sigdelset(&mask, PTHREAD_SIG_CANCEL); /* for debugging new threads */
+ sigdelset(&mask, SIGTRAP); /* for debugging purposes */
sigprocmask(SIG_SETMASK, &mask, NULL);
/* Raise our priority to match that of main thread */
__pthread_manager_adjust_prio(__pthread_main_thread->p_priority);
+ /* Synchronize debugging of the thread manager */
+ n = __libc_read(reqfd, (char *)&request, sizeof(request));
+ ASSERT(n == sizeof(request) && request.req_kind == REQ_DEBUG);
/* Enter server loop */
while(1) {
FD_ZERO(&readfds);
@@ -146,6 +159,14 @@ int __pthread_manager(void *arg)
return 0;
}
break;
+ case REQ_POST:
+ sem_post(request.req_args.post);
+ break;
+ case REQ_DEBUG:
+ /* Make gdb aware of new thread */
+ if (__pthread_threads_debug) raise(PTHREAD_SIG_CANCEL);
+ restart(request.req_thread);
+ break;
}
}
}
@@ -156,6 +177,7 @@ int __pthread_manager(void *arg)
static int pthread_start_thread(void *arg)
{
pthread_descr self = (pthread_descr) arg;
+ struct pthread_request request;
void * outcome;
/* Initialize special thread_self processing, if any. */
#ifdef INIT_THREAD_SELF
@@ -171,6 +193,14 @@ static int pthread_start_thread(void *arg)
if (self->p_start_args.schedpolicy >= 0)
__sched_setscheduler(self->p_pid, self->p_start_args.schedpolicy,
&self->p_start_args.schedparam);
+ /* Make gdb aware of new thread */
+ if (__pthread_threads_debug) {
+ request.req_thread = self;
+ request.req_kind = REQ_DEBUG;
+ __libc_write(__pthread_manager_request,
+ (char *) &request, sizeof(request));
+ suspend(self);
+ }
/* Run the thread code */
outcome = self->p_start_args.start_routine(self->p