Lock accesses to pt_flags and pt_cancel.

When disabling cancellation, clear the pt_cancel flag if it was set
and note the cancellation request with PT_FLAG_CS_PENDING. This avoids
a problem where a cancellation request entered but not acted upon before
pthread_setcanclstate(PTHREAD_CANCEL_DISABLE) is called would still be
aceted upon before cancellation was re-enabled.
This commit is contained in:
nathanw 2003-07-21 22:24:09 +00:00
parent 329747fb90
commit 0878df5d25
3 changed files with 70 additions and 45 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: pthread.c,v 1.27 2003/07/21 22:17:14 nathanw Exp $ */
/* $NetBSD: pthread.c,v 1.28 2003/07/21 22:24:09 nathanw Exp $ */
/*-
* Copyright (c) 2001,2002,2003 The NetBSD Foundation, Inc.
@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: pthread.c,v 1.27 2003/07/21 22:17:14 nathanw Exp $");
__RCSID("$NetBSD: pthread.c,v 1.28 2003/07/21 22:24:09 nathanw Exp $");
#include <err.h>
#include <errno.h>
@ -247,6 +247,7 @@ pthread__initthread(pthread_t self, pthread_t t)
t->pt_type = PT_THREAD_NORMAL;
t->pt_state = PT_STATE_RUNNABLE;
pthread_lockinit(&t->pt_statelock);
pthread_lockinit(&t->pt_flaglock);
t->pt_spinlocks = 0;
t->pt_next = NULL;
t->pt_exitval = NULL;
@ -396,6 +397,7 @@ pthread__idle(void)
*/
pthread_spinlock(self, &pthread__deadqueue_lock);
PTQ_INSERT_TAIL(&pthread__reidlequeue, self, pt_runq);
/* Don't need a flag lock; nothing else has a handle on this thread */
self->pt_flags |= PT_FLAG_IDLED;
pthread_spinunlock(self, &pthread__deadqueue_lock);
@ -420,14 +422,17 @@ pthread_exit(void *retval)
pthread_t self;
struct pt_clean_t *cleanup;
char *name;
int nt;
int nt, flags;
self = pthread__self();
SDPRINTF(("(pthread_exit %p) Exiting.\n", self));
SDPRINTF(("(pthread_exit %p) Exiting (status %p, flags %x, cancel %d).\n", self, retval, self->pt_flags, self->pt_cancel));
/* Disable cancellability. */
pthread_spinlock(self, &self->pt_flaglock);
self->pt_flags |= PT_FLAG_CS_DISABLED;
flags = self->pt_flags;
self->pt_cancel = 0;
pthread_spinunlock(self, &self->pt_flaglock);
/* Call any cancellation cleanup handlers */
while (!PTQ_EMPTY(&self->pt_cleanup_stack)) {
@ -441,11 +446,9 @@ pthread_exit(void *retval)
self->pt_exitval = retval;
pthread_spinlock(self, &self->pt_join_lock);
if (self->pt_flags & PT_FLAG_DETACHED) {
if (flags & PT_FLAG_DETACHED) {
name = self->pt_name;
self->pt_name = NULL;
pthread_spinunlock(self, &self->pt_join_lock);
if (name != NULL)
free(name);
@ -468,6 +471,7 @@ pthread_exit(void *retval)
pthread__block(self, &pthread__deadqueue_lock);
} else {
/* Note: name will be freed by the joiner. */
pthread_spinlock(self, &self->pt_join_lock);
pthread_spinlock(self, &pthread__allqueue_lock);
nthreads--;
nt = nthreads;
@ -510,14 +514,15 @@ pthread_join(pthread_t thread, void **valptr)
if (thread == self)
return EDEADLK;
pthread_spinlock(self, &thread->pt_join_lock);
pthread_spinlock(self, &thread->pt_flaglock);
if (thread->pt_flags & PT_FLAG_DETACHED) {
pthread_spinunlock(self, &thread->pt_join_lock);
pthread_spinunlock(self, &thread->pt_flaglock);
return EINVAL;
}
num = thread->pt_num;
pthread_spinlock(self, &thread->pt_join_lock);
while (thread->pt_state != PT_STATE_ZOMBIE) {
if ((thread->pt_state == PT_STATE_DEAD) ||
(thread->pt_flags & PT_FLAG_DETACHED) ||
@ -529,12 +534,14 @@ pthread_join(pthread_t thread, void **valptr)
* another chance to run.
*/
pthread_spinunlock(self, &thread->pt_join_lock);
pthread_spinunlock(self, &thread->pt_flaglock);
return ESRCH;
}
/*
* "I'm not dead yet!"
* "You will be soon enough."
*/
pthread_spinunlock(self, &thread->pt_flaglock);
pthread_spinlock(self, &self->pt_statelock);
if (self->pt_cancel) {
pthread_spinunlock(self, &self->pt_statelock);
@ -549,6 +556,7 @@ pthread_join(pthread_t thread, void **valptr)
PTQ_INSERT_TAIL(&thread->pt_joiners, self, pt_sleep);
pthread__block(self, &thread->pt_join_lock);
pthread_spinlock(self, &thread->pt_flaglock);
pthread_spinlock(self, &thread->pt_join_lock);
}
@ -557,6 +565,7 @@ pthread_join(pthread_t thread, void **valptr)
name = thread->pt_name;
thread->pt_name = NULL;
pthread_spinunlock(self, &thread->pt_join_lock);
pthread_spinunlock(self, &thread->pt_flaglock);
if (valptr != NULL)
*valptr = thread->pt_exitval;
@ -601,10 +610,12 @@ pthread_detach(pthread_t thread)
if (thread->pt_magic != PT_MAGIC)
return EINVAL;
pthread_spinlock(self, &thread->pt_flaglock);
pthread_spinlock(self, &thread->pt_join_lock);
if (thread->pt_flags & PT_FLAG_DETACHED) {
pthread_spinunlock(self, &thread->pt_join_lock);
pthread_spinunlock(self, &thread->pt_flaglock);
return EINVAL;
}
@ -614,6 +625,7 @@ pthread_detach(pthread_t thread)
pthread__sched_sleepers(self, &thread->pt_joiners);
pthread_spinunlock(self, &thread->pt_join_lock);
pthread_spinunlock(self, &thread->pt_flaglock);
return 0;
}
@ -701,7 +713,6 @@ int
pthread_cancel(pthread_t thread)
{
pthread_t self;
int flags;
if (!(thread->pt_state == PT_STATE_RUNNING ||
thread->pt_state == PT_STATE_RUNNABLE ||
@ -710,11 +721,12 @@ pthread_cancel(pthread_t thread)
return ESRCH;
self = pthread__self();
flags = thread->pt_flags;
flags |= PT_FLAG_CS_PENDING;
if ((flags & PT_FLAG_CS_DISABLED) == 0) {
pthread_spinlock(self, &thread->pt_flaglock);
thread->pt_flags |= PT_FLAG_CS_PENDING;
if ((thread->pt_flags & PT_FLAG_CS_DISABLED) == 0) {
thread->pt_cancel = 1;
pthread_spinunlock(self, &thread->pt_flaglock);
pthread_spinlock(self, &thread->pt_statelock);
if (thread->pt_state == PT_STATE_BLOCKED_SYS) {
/*
@ -746,9 +758,8 @@ pthread_cancel(pthread_t thread)
*/
}
pthread_spinunlock(self, &thread->pt_statelock);
}
thread->pt_flags = flags;
} else
pthread_spinunlock(self, &thread->pt_flaglock);
return 0;
}
@ -758,39 +769,45 @@ int
pthread_setcancelstate(int state, int *oldstate)
{
pthread_t self;
int flags;
int retval;
self = pthread__self();
flags = self->pt_flags;
retval = 0;
pthread_spinlock(self, &self->pt_flaglock);
if (oldstate != NULL) {
if (flags & PT_FLAG_CS_DISABLED)
if (self->pt_flags & PT_FLAG_CS_DISABLED)
*oldstate = PTHREAD_CANCEL_DISABLE;
else
*oldstate = PTHREAD_CANCEL_ENABLE;
}
if (state == PTHREAD_CANCEL_DISABLE)
flags |= PT_FLAG_CS_DISABLED;
else if (state == PTHREAD_CANCEL_ENABLE) {
flags &= ~PT_FLAG_CS_DISABLED;
if (state == PTHREAD_CANCEL_DISABLE) {
self->pt_flags |= PT_FLAG_CS_DISABLED;
if (self->pt_cancel) {
self->pt_flags |= PT_FLAG_CS_PENDING;
self->pt_cancel = 0;
}
} else if (state == PTHREAD_CANCEL_ENABLE) {
self->pt_flags &= ~PT_FLAG_CS_DISABLED;
/*
* If a cancellation was requested while cancellation
* was disabled, note that fact for future
* cancellation tests.
*/
if (flags & PT_FLAG_CS_PENDING) {
if (self->pt_flags & PT_FLAG_CS_PENDING) {
self->pt_cancel = 1;
/* This is not a deferred cancellation point. */
if (flags & PT_FLAG_CS_ASYNC)
if (self->pt_flags & PT_FLAG_CS_ASYNC) {
pthread_spinunlock(self, &self->pt_flaglock);
pthread_exit(PTHREAD_CANCELED);
}
}
} else
return EINVAL;
retval = EINVAL;
self->pt_flags = flags;
return 0;
pthread_spinunlock(self, &self->pt_flaglock);
return retval;
}
@ -798,30 +815,33 @@ int
pthread_setcanceltype(int type, int *oldtype)
{
pthread_t self;
int flags;
int retval;
self = pthread__self();
flags = self->pt_flags;
retval = 0;
pthread_spinlock(self, &self->pt_flaglock);
if (oldtype != NULL) {
if (flags & PT_FLAG_CS_ASYNC)
if (self->pt_flags & PT_FLAG_CS_ASYNC)
*oldtype = PTHREAD_CANCEL_ASYNCHRONOUS;
else
*oldtype = PTHREAD_CANCEL_DEFERRED;
}
if (type == PTHREAD_CANCEL_ASYNCHRONOUS) {
flags |= PT_FLAG_CS_ASYNC;
if (self->pt_cancel)
self->pt_flags |= PT_FLAG_CS_ASYNC;
if (self->pt_cancel) {
pthread_spinunlock(self, &self->pt_flaglock);
pthread_exit(PTHREAD_CANCELED);
}
} else if (type == PTHREAD_CANCEL_DEFERRED)
flags &= ~PT_FLAG_CS_ASYNC;
self->pt_flags &= ~PT_FLAG_CS_ASYNC;
else
return EINVAL;
retval = EINVAL;
self->pt_flags = flags;
return 0;
pthread_spinunlock(self, &self->pt_flaglock);
return retval;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: pthread_sa.c,v 1.12 2003/06/26 01:28:14 nathanw Exp $ */
/* $NetBSD: pthread_sa.c,v 1.13 2003/07/21 22:24:09 nathanw Exp $ */
/*-
* Copyright (c) 2001 The NetBSD Foundation, Inc.
@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: pthread_sa.c,v 1.12 2003/06/26 01:28:14 nathanw Exp $");
__RCSID("$NetBSD: pthread_sa.c,v 1.13 2003/07/21 22:24:09 nathanw Exp $");
#include <err.h>
#include <errno.h>
@ -89,7 +89,7 @@ void
pthread__upcall(int type, struct sa_t *sas[], int ev, int intr, void *arg)
{
pthread_t t, self, next, intqueue, schedqueue;
int first = 1;
int flags, first = 1;
siginfo_t *si;
PTHREADD_ADD(PTHREADD_UPCALLS);
@ -158,7 +158,10 @@ pthread__upcall(int type, struct sa_t *sas[], int ev, int intr, void *arg)
* it was in the kernel.
*/
t = pthread__sa_id(sas[1]);
if (t->pt_flags & PT_FLAG_SIGDEFERRED)
pthread_spinlock(self, &t->pt_flaglock);
flags = t->pt_flags;
pthread_spinunlock(self, &t->pt_flaglock);
if (flags & PT_FLAG_SIGDEFERRED)
pthread__signal_deferred(self, t);
break;
case SA_UPCALL_SIGNAL:

View File

@ -1,4 +1,4 @@
/* $NetBSD: pthread_sig.c,v 1.15 2003/07/17 18:15:21 fvdl Exp $ */
/* $NetBSD: pthread_sig.c,v 1.16 2003/07/21 22:24:09 nathanw Exp $ */
/*-
* Copyright (c) 2001 The NetBSD Foundation, Inc.
@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: pthread_sig.c,v 1.15 2003/07/17 18:15:21 fvdl Exp $");
__RCSID("$NetBSD: pthread_sig.c,v 1.16 2003/07/21 22:24:09 nathanw Exp $");
/* We're interposing a specific version of the signal interface. */
#define __LIBC12_SOURCE__
@ -780,7 +780,9 @@ pthread__kill(pthread_t self, pthread_t target, int sig, int code)
*/
__sigaddset14(&target->pt_sigblocked, sig);
__sigaddset14(&target->pt_sigmask, sig);
pthread_spinlock(self, &target->pt_flaglock);
target->pt_flags |= PT_FLAG_SIGDEFERRED;
pthread_spinunlock(self, &target->pt_flaglock);
pthread_spinunlock(self, &target->pt_statelock);
_lwp_wakeup(target->pt_blockedlwp);
return;