Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 2 Jan 2005 13:26:32 GMT
From:      David Xu <davidxu@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 68138 for review
Message-ID:  <200501021326.j02DQWCV013887@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=68138

Change 68138 by davidxu@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@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@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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200501021326.j02DQWCV013887>