diff options
Diffstat (limited to 'linuxthreads')
| -rw-r--r-- | linuxthreads/ChangeLog | 29 | ||||
| -rw-r--r-- | linuxthreads/attr.c | 8 | ||||
| -rw-r--r-- | linuxthreads/cancel.c | 6 | ||||
| -rw-r--r-- | linuxthreads/condvar.c | 79 | ||||
| -rw-r--r-- | linuxthreads/internals.h | 28 | ||||
| -rw-r--r-- | linuxthreads/join.c | 28 | ||||
| -rw-r--r-- | linuxthreads/manager.c | 79 | ||||
| -rw-r--r-- | linuxthreads/mutex.c | 122 | ||||
| -rw-r--r-- | linuxthreads/pthread.c | 89 | ||||
| -rw-r--r-- | linuxthreads/ptlongjmp.c | 2 | ||||
| -rw-r--r-- | linuxthreads/queue.h | 57 | ||||
| -rw-r--r-- | linuxthreads/rwlock.c | 47 | ||||
| -rw-r--r-- | linuxthreads/semaphore.c | 236 | ||||
| -rw-r--r-- | linuxthreads/semaphore.h | 7 | ||||
| -rw-r--r-- | linuxthreads/signals.c | 89 | ||||
| -rw-r--r-- | linuxthreads/spinlock.c | 123 | ||||
| -rw-r--r-- | linuxthreads/spinlock.h | 53 | ||||
| -rw-r--r-- | linuxthreads/sysdeps/i386/pt-machine.h | 6 | ||||
| -rw-r--r-- | linuxthreads/sysdeps/pthread/pthread.h | 38 | ||||
| -rw-r--r-- | linuxthreads/sysdeps/unix/sysv/linux/bits/posix_opt.h | 8 |
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 |
