PERFORCE change 68138 for review
David Xu
davidxu at FreeBSD.org
Sun Jan 2 13:26:33 GMT 2005
http://perforce.freebsd.org/chv.cgi?CH=68138
Change 68138 by davidxu at davidxu_tiger on 2005/01/02 13:26:06
simplicy cancellation code by not using thread lock.
Affected files ...
.. //depot/projects/davidxu_thread/src/lib/libthread/thread/thr_cancel.c#5 edit
.. //depot/projects/davidxu_thread/src/lib/libthread/thread/thr_exit.c#5 edit
.. //depot/projects/davidxu_thread/src/lib/libthread/thread/thr_mutex.c#8 edit
.. //depot/projects/davidxu_thread/src/lib/libthread/thread/thr_private.h#10 edit
.. //depot/projects/davidxu_thread/src/lib/libthread/thread/thr_sig.c#5 edit
Differences ...
==== //depot/projects/davidxu_thread/src/lib/libthread/thread/thr_cancel.c#5 (text+ko) ====
@@ -1,8 +1,32 @@
/*
- * David Leonard <d at openbsd.org>, 1999. Public domain.
- * $FreeBSD: src/lib/libpthread/thread/thr_cancel.c,v 1.31 2003/12/09 02:20:56 davidxu Exp $
+ * Copyright (c) 2005, David Xu<davidxu at freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
*/
-#include <sys/errno.h>
+
#include <pthread.h>
#include "thr_private.h"
@@ -11,183 +35,124 @@
__weak_reference(_pthread_setcanceltype, pthread_setcanceltype);
__weak_reference(_pthread_testcancel, pthread_testcancel);
-static inline int
-checkcancel(struct pthread *curthread)
-{
- /*
- * Don't do cancellation again if it was already in progress.
- */
- if ((curthread->cancelflags &
- (THR_CANCEL_EXITING | THR_CANCELLING | THR_CANCEL_DISABLE |
- THR_CANCEL_NEEDED)) == THR_CANCEL_NEEDED) {
- curthread->cancelflags |= THR_CANCELLING;
- return (1);
- }
- return (0);
-}
-
-static inline void
-testcancel(struct pthread *curthread)
-{
- if (checkcancel(curthread) != 0) {
- /* Unlock before exiting: */
- THR_UNLOCK(curthread);
- pthread_exit(PTHREAD_CANCELED);
- PANIC("cancel");
- }
-}
-
int
_pthread_cancel(pthread_t pthread)
{
struct pthread *curthread = _get_curthread();
- long tid = -1;
- int ret;
+ int oldval, newval, ret;
+
+ if ((ret = _thr_ref_add(curthread, pthread, 0)) != 0)
+ return (ret);
+ do {
+ oldval = pthread->cancelflags;
+ if (oldval & THR_CANCEL_NEEDED)
+ break;
+ newval = oldval | THR_CANCEL_NEEDED;
+ } while (!atomic_cmpset_acq_int(&pthread->cancelflags, oldval, newval));
+
+ if (!(oldval & THR_CANCEL_NEEDED) && SHOULD_ASYNC_CANCEL(newval))
+ thr_kill(pthread->tid, SIGCANCEL);
- THREAD_LIST_LOCK(curthread);
- if ((ret = _thr_find_thread(curthread, pthread, 0)) == 0) {
- /*
- * Take the thread's lock while we change the cancel flags.
- */
- THR_THREAD_LOCK(curthread, pthread);
- THREAD_LIST_UNLOCK(curthread);
- if (pthread->cancelflags &
- (THR_CANCELLING | THR_CANCEL_EXITING)) {
- THR_THREAD_UNLOCK(curthread, pthread);
- return (0);
- }
- pthread->cancelflags |= THR_CANCEL_NEEDED;
- if ((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0 &&
- ((pthread->cancelflags & THR_CANCEL_AT_POINT) != 0 ||
- (pthread->cancelflags & THR_CANCEL_ASYNCHRONOUS) != 0)) {
- tid = pthread->tid;
- thr_kill(tid, SIGCANCEL);
- }
- /*
- * Release the thread's lock and remove the
- * reference:
- */
- THR_THREAD_UNLOCK(curthread, pthread);
- } else {
- THREAD_LIST_UNLOCK(curthread);
- }
- return (ret);
+ _thr_ref_delete(curthread, pthread);
+ return (0);
}
int
_pthread_setcancelstate(int state, int *oldstate)
{
- struct pthread *curthread = _get_curthread();
- int need_exit = 0;
- int ostate;
- int ret;
+ struct pthread *curthread = _get_curthread();
+ int oldval, newval;
+
+ if (state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE)
+ return (EINVAL);
- /* Take the thread's lock while fiddling with the state: */
- THR_LOCK(curthread);
+ for (;;) {
+ oldval = curthread->cancelflags;
+ newval = (state == PTHREAD_CANCEL_DISABLE ?
+ oldval | THR_CANCEL_DISABLE :
+ oldval & ~THR_CANCEL_DISABLE);
- if (curthread->cancelflags & THR_CANCEL_DISABLE)
- ostate = PTHREAD_CANCEL_DISABLE;
- else
- ostate = PTHREAD_CANCEL_ENABLE;
+ if (oldstate != NULL)
+ *oldstate = ((oldval & THR_CANCEL_DISABLE) ?
+ PTHREAD_CANCEL_DISABLE : PTHREAD_CANCEL_ENABLE);
- switch (state) {
- case PTHREAD_CANCEL_ENABLE:
- curthread->cancelflags &= ~THR_CANCEL_DISABLE;
- if ((curthread->cancelflags & THR_CANCEL_ASYNCHRONOUS) != 0)
- need_exit = checkcancel(curthread);
- ret = 0;
- break;
- case PTHREAD_CANCEL_DISABLE:
- curthread->cancelflags |= THR_CANCEL_DISABLE;
- ret = 0;
- break;
- default:
- ret = EINVAL;
- }
+ if (oldval == newval)
+ break;
- THR_UNLOCK(curthread);
- if (need_exit != 0) {
- pthread_exit(PTHREAD_CANCELED);
- PANIC("cancel");
+ if (atomic_cmpset_acq_int(&curthread->cancelflags, oldval,
+ newval)) {
+ if (SHOULD_CANCEL(newval))
+ pthread_exit(PTHREAD_CANCELED);
+ break;
+ }
}
- if (ret == 0 && oldstate != NULL)
- *oldstate = ostate;
-
- return (ret);
+
+ return (0);
}
int
_pthread_setcanceltype(int type, int *oldtype)
{
struct pthread *curthread = _get_curthread();
- int need_exit = 0;
- int otype;
- int ret;
+ int oldval, newval;
- /* Take the thread's lock while fiddling with the state: */
- THR_LOCK(curthread);
+ if (type != PTHREAD_CANCEL_DEFERRED &&
+ type != PTHREAD_CANCEL_ASYNCHRONOUS)
+ return (EINVAL);
- if (curthread->cancelflags & THR_CANCEL_ASYNCHRONOUS)
- otype = PTHREAD_CANCEL_ASYNCHRONOUS;
- else
- otype = PTHREAD_CANCEL_DEFERRED;
- switch (type) {
- case PTHREAD_CANCEL_ASYNCHRONOUS:
- curthread->cancelflags |= THR_CANCEL_ASYNCHRONOUS;
- need_exit = checkcancel(curthread);
- ret = 0;
- break;
- case PTHREAD_CANCEL_DEFERRED:
- curthread->cancelflags &= ~THR_CANCEL_ASYNCHRONOUS;
- ret = 0;
- break;
- default:
- ret = EINVAL;
+ for (;;) {
+ oldval = curthread->cancelflags;
+ if (oldtype != NULL)
+ *oldtype = ((oldval & THR_CANCEL_AT_POINT) ?
+ PTHREAD_CANCEL_ASYNCHRONOUS :
+ PTHREAD_CANCEL_DEFERRED);
+ newval = (type == PTHREAD_CANCEL_ASYNCHRONOUS ?
+ oldval | THR_CANCEL_AT_POINT :
+ oldval & ~THR_CANCEL_AT_POINT);
+ if (oldval == newval)
+ break;
+ if (atomic_cmpset_acq_int(&curthread->cancelflags, oldval,
+ newval)) {
+ if (SHOULD_CANCEL(newval))
+ pthread_exit(PTHREAD_CANCELED);
+ break;
+ }
}
-
- THR_UNLOCK(curthread);
- if (need_exit != 0) {
- pthread_exit(PTHREAD_CANCELED);
- PANIC("cancel");
- }
- if (ret == 0 && oldtype != NULL)
- *oldtype = otype;
-
- return (ret);
+
+ return (0);
}
void
_pthread_testcancel(void)
{
- struct pthread *curthread = _get_curthread();
-
- THR_LOCK(curthread);
- testcancel(curthread);
- THR_UNLOCK(curthread);
+ struct pthread *curthread = _get_curthread();
+
+ if (SHOULD_CANCEL(curthread->cancelflags))
+ pthread_exit(PTHREAD_CANCELED);
}
int
_thr_cancel_enter(struct pthread *curthread)
{
- int old;
+ int oldval;
- /* Look for a cancellation before we block: */
- THR_LOCK(curthread);
- old = curthread->cancelflags;
- if (!(curthread->cancelflags & THR_CANCEL_AT_POINT)) {
- testcancel(curthread);
- curthread->cancelflags |= THR_CANCEL_AT_POINT;
- }
- THR_UNLOCK(curthread);
- return (old);
+ for (;;) {
+ oldval = curthread->cancelflags;
+ if (oldval & THR_CANCEL_AT_POINT)
+ break;
+ int newval = oldval | THR_CANCEL_AT_POINT;
+ if (atomic_cmpset_acq_int(&curthread->cancelflags, oldval,
+ newval)) {
+ if (SHOULD_CANCEL(newval))
+ pthread_exit(PTHREAD_CANCELED);
+ }
+ }
+ return (oldval);
}
void
_thr_cancel_leave(struct pthread *curthread, int previous)
{
if (!(previous & THR_CANCEL_AT_POINT))
- return;
- THR_LOCK(curthread);
- curthread->cancelflags &= ~THR_CANCEL_AT_POINT;
- THR_UNLOCK(curthread);
+ atomic_clear_int(&curthread->cancelflags, THR_CANCEL_AT_POINT);
}
==== //depot/projects/davidxu_thread/src/lib/libthread/thread/thr_exit.c#5 (text+ko) ====
@@ -101,9 +101,7 @@
* Flag this thread as exiting. Threads should now be prevented
* from joining to this thread.
*/
- THR_LOCK(curthread);
- curthread->cancelflags |= THR_CANCEL_EXITING;
- THR_UNLOCK(curthread);
+ atomic_set_int(&curthread->cancelflags, THR_CANCEL_EXITING);
_thr_exit_cleanup();
==== //depot/projects/davidxu_thread/src/lib/libthread/thread/thr_mutex.c#8 (text+ko) ====
==== //depot/projects/davidxu_thread/src/lib/libthread/thread/thr_private.h#10 (text+ko) ====
@@ -177,6 +177,7 @@
volatile long c_seqno;
volatile long c_waiters;
volatile long c_wakeups;
+ long c_count;
long c_flags;
};
@@ -412,9 +413,15 @@
#define THR_CANCEL_DISABLE 0x0001
#define THR_CANCEL_EXITING 0x0002
#define THR_CANCEL_AT_POINT 0x0004
-#define THR_CANCELLING 0x0008
-#define THR_CANCEL_NEEDED 0x0010
-#define THR_CANCEL_ASYNCHRONOUS 0x0020
+#define THR_CANCEL_NEEDED 0x0008
+#define SHOULD_CANCEL(val) \
+ (((val) & (THR_CANCEL_DISABLE | THR_CANCEL_EXITING | \
+ THR_CANCEL_NEEDED)) == THR_CANCEL_NEEDED)
+
+#define SHOULD_ASYNC_CANCEL(val) \
+ (((val) & (THR_CANCEL_DISABLE | THR_CANCEL_EXITING | \
+ THR_CANCEL_NEEDED | THR_CANCEL_AT_POINT)) == \
+ (THR_CANCEL_NEEDED | THR_CANCEL_AT_POINT))
int cancelflags;
/* Thread temporary signal mask. */
==== //depot/projects/davidxu_thread/src/lib/libthread/thread/thr_sig.c#5 (text+ko) ====
@@ -186,10 +186,8 @@
static void
thr_cancel_handler(struct pthread *curthread)
{
- if ((curthread->cancelflags &
- (THR_CANCEL_AT_POINT | THR_CANCEL_ASYNCHRONOUS))) {
+ if (curthread->cancelflags & THR_CANCEL_AT_POINT)
pthread_testcancel();
- }
_thr_suspend_check(curthread);
}
@@ -197,7 +195,6 @@
void
_thr_suspend_check(struct pthread *curthread)
{
-#if 0
sigset_t set;
long cycle;
@@ -218,7 +215,6 @@
curthread->flags &= ~THR_FLAGS_SUSPENDED;
}
THR_UNLOCK(curthread);
-#endif
}
void
More information about the p4-projects
mailing list