From 81fda5bdd511f0da950272881acbd819ddcb7d7d Mon Sep 17 00:00:00 2001
From: Mike Makonnen <mtm@FreeBSD.org>
Date: Fri, 26 Mar 2004 14:47:54 +0000
Subject: [PATCH] o The mutex locking functions aren't normally cancellation
 points. But,   we still have to DTRT when an asynchronously cancellable
 thread is   cancelled while waiting for a mutex. o While dequeueing a waiting
 mutex don't skip a thread if it has   a cancel pending. Only skip it if it is
 also async cancellable.

---
 lib/libthr/thread/thr_mutex.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/lib/libthr/thread/thr_mutex.c b/lib/libthr/thread/thr_mutex.c
index e3dc816fd73f..774527b1a9ef 100644
--- a/lib/libthr/thread/thr_mutex.c
+++ b/lib/libthr/thread/thr_mutex.c
@@ -324,7 +324,6 @@ mutex_lock_common(pthread_mutex_t * mutex, int nonblock,
 	PTHREAD_ASSERT(((*mutex)->m_protocol >= PTHREAD_PRIO_NONE &&
 	    (*mutex)->m_protocol <= PTHREAD_PRIO_PROTECT),
 	    "Invalid mutex protocol"); 
-	pthread_testcancel();
 	_SPINLOCK(&(*mutex)->lock);
 
 	/*
@@ -418,7 +417,6 @@ mutex_lock_common(pthread_mutex_t * mutex, int nonblock,
 	_thread_critical_exit(curthread);
 out:
 	_SPINUNLOCK(&(*mutex)->lock);
-	pthread_testcancel();
 	return (error);
 }
 
@@ -771,7 +769,10 @@ mutex_queue_deq(pthread_mutex_t mutex)
 		 * Only exit the loop if the thread hasn't been
 		 * cancelled.
 		 */
-		if ((pthread->cancelflags & PTHREAD_CANCELLING) == 0 &&
+		if (((pthread->cancelflags & PTHREAD_CANCELLING) == 0 ||
+		    (pthread->cancelflags & PTHREAD_CANCEL_DISABLE) != 0 ||
+		    ((pthread->cancelflags & PTHREAD_CANCELLING) != 0 &&
+		    (pthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0)) &&
 		    pthread->state == PS_MUTEX_WAIT)
 			break;
 		else
@@ -887,6 +888,14 @@ get_mcontested(pthread_mutex_t mutexp, const struct timespec *abstime)
 	_thread_critical_enter(curthread);
 	mutex_queue_enq(mutexp, curthread);
 	do {
+		if ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0 &&
+		    (curthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0 &&
+		    (curthread->cancelflags & PTHREAD_CANCELLING) != 0) {
+			mutex_queue_remove(mutexp, curthread);
+			_thread_critical_exit(curthread);
+			_SPINUNLOCK(&mutexp->lock);
+			pthread_testcancel();
+		}
 		PTHREAD_SET_STATE(curthread, PS_MUTEX_WAIT);
 		curthread->data.mutex = mutexp;
 		_thread_critical_exit(curthread);