Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/nathanw_sa]: src/lib/libpthread Cancellation support.
details: https://anonhg.NetBSD.org/src/rev/9d331ddacc61
branches: nathanw_sa
changeset: 505563:9d331ddacc61
user: nathanw <nathanw%NetBSD.org@localhost>
date: Mon Jan 28 19:05:48 2002 +0000
description:
Cancellation support.
This includes implementing pthread_cancel() and pthread_testcancel(),
making pthread_join() and pthread_cond_wait() cancellation points,
introducing new states to distinguish waiting on a sleep queue
from waiting in the kernel, and introducing a locking protocol around
changing a thread's run state.
diffstat:
lib/libpthread/pthread.c | 90 ++++++++++++++++++++++++++++++++++++-----
lib/libpthread/pthread.h | 6 +-
lib/libpthread/pthread_int.h | 27 +++++++++--
lib/libpthread/pthread_mutex.c | 16 ++++++-
4 files changed, 116 insertions(+), 23 deletions(-)
diffs (truncated from 316 to 300 lines):
diff -r 8be8b0af7b62 -r 9d331ddacc61 lib/libpthread/pthread.c
--- a/lib/libpthread/pthread.c Mon Jan 28 19:03:09 2002 +0000
+++ b/lib/libpthread/pthread.c Mon Jan 28 19:05:48 2002 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: pthread.c,v 1.1.2.13 2001/12/30 02:18:17 nathanw Exp $ */
+/* $NetBSD: pthread.c,v 1.1.2.14 2002/01/28 19:05:48 nathanw Exp $ */
/*-
* Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -39,6 +39,7 @@
#include <assert.h>
#include <err.h>
#include <errno.h>
+#include <lwp.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
@@ -82,8 +83,10 @@
void pthread_init(void)
{
pthread_t first;
+ int retval;
extern int __isthreaded;
-
+ extern timer_t pthread_alarmtimer;
+ struct sigevent ev;
#ifdef PTHREAD__DEBUG
pthread__debug_init();
#endif
@@ -95,7 +98,13 @@
PTQ_INIT(&reidlequeue);
PTQ_INIT(&runqueue);
PTQ_INIT(&idlequeue);
-
+
+ ev.sigev_notify = SIGEV_SA;
+ ev.sigev_signo = 0;
+ ev.sigev_value.sival_int = 0;
+ retval = timer_create(CLOCK_REALTIME, &ev, &pthread_alarmtimer);
+ if (retval)
+ err(1, "timer_create");
/* Create the thread structure corresponding to main() */
pthread__initmain(&first);
pthread__initthread(first);
@@ -137,6 +146,7 @@
t->pt_magic = PT_MAGIC;
t->pt_type = PT_THREAD_NORMAL;
t->pt_state = PT_STATE_RUNNABLE;
+ pthread_lockinit(&t->pt_statelock);
t->pt_spinlocks = 0;
t->pt_next = NULL;
t->pt_exitval = NULL;
@@ -149,7 +159,9 @@
t->pt_sleepuc = NULL;
sigemptyset(&t->pt_siglist);
sigemptyset(&t->pt_sigmask);
+ pthread_lockinit(&t->pt_siglock);
PTQ_INIT(&t->pt_joiners);
+ pthread_lockinit(&t->pt_join_lock);
PTQ_INIT(&t->pt_cleanup_stack);
memset(&t->pt_specific, 0, sizeof(int) * PTHREAD_KEYS_MAX);
#ifdef PTHREAD__DEBUG
@@ -274,6 +286,9 @@
self = pthread__self();
+ /* Disable cancellability. */
+ self->pt_flags |= PT_FLAG_CS_DISABLED;
+
/* Call any cancellation cleanup handlers */
while (!PTQ_EMPTY(&self->pt_cleanup_stack)) {
cleanup = PTQ_FIRST(&self->pt_cleanup_stack);
@@ -340,6 +355,10 @@
return EINVAL;
self = pthread__self();
+
+ if (thread == self)
+ return EDEADLK;
+
pthread_spinlock(self, &thread->pt_join_lock);
if (thread->pt_flags & PT_FLAG_DETACHED) {
@@ -353,11 +372,17 @@
* "I'm not dead yet!"
* "You will be soon enough."
*/
- PTQ_INSERT_TAIL(&thread->pt_joiners, self, pt_sleep);
+ pthread_spinlock(self, &self->pt_statelock);
+ if (self->pt_cancel) {
+ pthread_spinunlock(self, &self->pt_statelock);
+ pthread_spinunlock(self, &thread->pt_join_lock);
+ pthread_exit(PTHREAD_CANCELED);
+ }
+ self->pt_state = PT_STATE_BLOCKED_QUEUE;
+ pthread_spinunlock(self, &self->pt_statelock);
- self->pt_state = PT_STATE_BLOCKED;
+ PTQ_INSERT_TAIL(&thread->pt_joiners, self, pt_sleep);
pthread__block(self, &thread->pt_join_lock);
-
pthread_spinlock(self, &thread->pt_join_lock);
}
@@ -387,7 +412,6 @@
return 0;
}
-
int
pthread_equal(pthread_t t1, pthread_t t2)
{
@@ -532,7 +556,48 @@
int
pthread_cancel(pthread_t thread)
{
- /* XXX finish */
+ pthread_t self;
+ int flags;
+
+ if (!(thread->pt_state == PT_STATE_RUNNABLE ||
+ thread->pt_state == PT_STATE_BLOCKED_QUEUE ||
+ thread->pt_state == PT_STATE_BLOCKED_SYS))
+ return ESRCH;
+
+ self = pthread__self();
+ flags = thread->pt_flags;
+
+ flags |= PT_FLAG_CS_PENDING;
+ if ((flags & PT_FLAG_CS_DISABLED) == 0) {
+ thread->pt_cancel = 1;
+ pthread_spinlock(self, &thread->pt_statelock);
+ if (thread->pt_state == PT_STATE_BLOCKED_SYS) {
+ /* It's sleeping in the kernel. If we can
+ * wake it up, it will notice the cancellation
+ * when it returns. If we can't wake it up...
+ * there's not much to be done about it.
+ */
+ _lwp_wakeup(thread->pt_blockedlwp);
+ } else if (thread->pt_state == PT_STATE_BLOCKED_QUEUE) {
+ /* We're blocked somewhere (pthread__block()
+ * was called. Cause it to wakeup and the
+ * caller will check for the cancellation.
+ */
+ pthread_spinlock(self, thread->pt_sleeplock);
+ PTQ_REMOVE(thread->pt_sleepq, thread,
+ pt_sleep);
+ pthread_spinunlock(self, thread->pt_sleeplock);
+ pthread__sched(self, thread);
+ } else {
+ /* Nothing. The target thread is running and will
+ * notice at the next deferred cancellation point.
+ */
+ }
+ pthread_spinunlock(self, &thread->pt_statelock);
+ }
+
+ thread->pt_flags = flags;
+
return 0;
}
@@ -567,7 +632,7 @@
self->pt_cancel = 1;
/* This is not a deferred cancellation point. */
if (flags & PT_FLAG_CS_ASYNC)
- pthread_exit(PTHREAD_CANCELLED);
+ pthread_exit(PTHREAD_CANCELED);
}
} else
return EINVAL;
@@ -597,7 +662,7 @@
if (type == PTHREAD_CANCEL_ASYNCHRONOUS) {
flags |= PT_FLAG_CS_ASYNC;
if (self->pt_cancel)
- pthread_exit(PTHREAD_CANCELLED);
+ pthread_exit(PTHREAD_CANCELED);
} else if (type == PTHREAD_CANCEL_DEFERRED)
flags &= ~PT_FLAG_CS_ASYNC;
else
@@ -615,7 +680,8 @@
pthread_t self;
self = pthread__self();
- pthread__testcancel(self);
+ if (self->pt_cancel)
+ pthread_exit(PTHREAD_CANCELED);
}
@@ -624,7 +690,7 @@
{
if (self->pt_cancel)
- pthread_exit(PTHREAD_CANCELLED);
+ pthread_exit(PTHREAD_CANCELED);
}
void
diff -r 8be8b0af7b62 -r 9d331ddacc61 lib/libpthread/pthread.h
--- a/lib/libpthread/pthread.h Mon Jan 28 19:03:09 2002 +0000
+++ b/lib/libpthread/pthread.h Mon Jan 28 19:05:48 2002 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: pthread.h,v 1.1.2.7 2001/12/30 02:14:41 nathanw Exp $ */
+/* $NetBSD: pthread.h,v 1.1.2.8 2002/01/28 19:05:49 nathanw Exp $ */
/*-
* Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -136,11 +136,11 @@
#define PTHREAD_CANCEL_DISABLE 1
/* POSIX 1003.1-2001, section 2.5.9.3: "The symbolic constant
- * PTHREAD_CANCELLED expands to a constant expression of type (void *)
+ * PTHREAD_CANCELED expands to a constant expression of type (void *)
* whose value matches no pointer to an object in memory nor the value
* NULL."
*/
-#define PTHREAD_CANCELLED ((void *) 1)
+#define PTHREAD_CANCELED ((void *) 1)
#define _POSIX_THREADS
diff -r 8be8b0af7b62 -r 9d331ddacc61 lib/libpthread/pthread_int.h
--- a/lib/libpthread/pthread_int.h Mon Jan 28 19:03:09 2002 +0000
+++ b/lib/libpthread/pthread_int.h Mon Jan 28 19:05:48 2002 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: pthread_int.h,v 1.1.2.17 2001/12/30 02:13:00 nathanw Exp $ */
+/* $NetBSD: pthread_int.h,v 1.1.2.18 2002/01/28 19:05:49 nathanw Exp $ */
/*-
* Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -62,9 +62,11 @@
int pt_type; /* normal, upcall, or idle */
int pt_state; /* running, blocked, etc. */
- int pt_flags;
+ pthread_spin_t pt_statelock; /* lock on pt_state */
+ int pt_flags; /* see PT_FLAG_* below */
int pt_cancel; /* Deferred cancellation */
int pt_spinlocks; /* Number of spinlocks held. */
+ int pt_blockedlwp; /* LWP/SA number when blocked */
int pt_errno; /* Thread-specific errno. */
@@ -74,6 +76,10 @@
PTQ_ENTRY(pthread_st) pt_allq;
/* Entry on the sleep queue (xxx should be same as run queue?) */
PTQ_ENTRY(pthread_st) pt_sleep;
+ /* Queue we're sleeping on */
+ struct pthread_queue_t *pt_sleepq;
+ /* Lock protecting that queue */
+ pthread_spin_t *pt_sleeplock;
stack_t pt_stack; /* Our stack */
ucontext_t *pt_uc; /* Saved context when we're stopped */
@@ -139,10 +145,11 @@
/* Thread states */
#define PT_STATE_RUNNABLE 1
-#define PT_STATE_BLOCKED 2
-#define PT_STATE_ZOMBIE 3
-#define PT_STATE_DEAD 4
-#define PT_STATE_RECYCLABLE 5
+#define PT_STATE_BLOCKED_SYS 2
+#define PT_STATE_BLOCKED_QUEUE 3
+#define PT_STATE_ZOMBIE 4
+#define PT_STATE_DEAD 5
+#define PT_STATE_RECYCLABLE 6
/* Flag values */
@@ -200,6 +207,14 @@
void pthread__sa_start(void);
void pthread__sa_recycle(pthread_t old, pthread_t new);
+/* Alarm code */
+void *pthread__alarm_add(pthread_t, const struct timespec *,
+ void (*)(void *), void *);
+void pthread__alarm_del(pthread_t, void *);
+int pthread__alarm_fired(void *);
+void pthread__alarm_process(pthread_t self, void *arg);
+
+
#include "pthread_md.h"
int _getcontext_u(ucontext_t *);
diff -r 8be8b0af7b62 -r 9d331ddacc61 lib/libpthread/pthread_mutex.c
--- a/lib/libpthread/pthread_mutex.c Mon Jan 28 19:03:09 2002 +0000
+++ b/lib/libpthread/pthread_mutex.c Mon Jan 28 19:05:48 2002 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: pthread_mutex.c,v 1.1.2.6 2001/08/08 16:36:29 nathanw Exp $ */
+/* $NetBSD: pthread_mutex.c,v 1.1.2.7 2002/01/28 19:05:49 nathanw Exp $ */
/*-
* Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -117,7 +117,19 @@
*/
if (mutex->ptm_lock == __SIMPLELOCK_LOCKED) {
PTQ_INSERT_TAIL(&mutex->ptm_blocked, self, pt_sleep);
- self->pt_state = PT_STATE_BLOCKED;
Home |
Main Index |
Thread Index |
Old Index