Patch to fix cv_wait return values

John Baldwin jhb at FreeBSD.org
Mon Jul 19 10:53:10 PDT 2004


I have a patch to try to sync up the semantics of the return values of the 
cv_wait() functions with msleep().  The patch is at 
http://people.FreeBSD.org/~jhb/patches/cv_retval.patch and is inline below.  
If people could test it ok and verify that the patch is correct I'd 
appreciate it.  Thanks.

--- //depot/projects/smpng/sys/kern/kern_condvar.c	2004/06/29 02:54:29
+++ //depot/user/jhb/lock/kern/kern_condvar.c	2004/07/09 18:16:47
@@ -170,12 +170,28 @@
 		 * procs or panic below, in case this is the idle process and
 		 * already asleep.
 		 */
-		return 0;
+		return (0);
 	}
 
 	sq = sleepq_lookup(cvp);
 
-	/* XXX: Missing the threading checks from msleep! */
+	/*
+	 * Don't bother sleeping if we are exiting and not the exiting
+	 * thread or if our thread is marked as interrupted.
+	 */
+	mtx_lock_spin(&sched_lock);
+	if (p->p_flag & P_SA || p->p_numthreads > 1) {
+		if ((p->p_flag & P_WEXIT) && p->p_singlethread != td)
+			rval = EINTR;
+		else if (td->td_flags & TDF_INTERRUPT)
+			rval = td->td_intrval;
+		if (rval != 0) {
+			mtx_unlock_spin(&sched_lock);
+			sleepq_release(cvp);
+			return (rval);
+		}
+	}
+	mtx_unlock_spin(&sched_lock);
 
 	cvp->cv_waiters++;
 	DROP_GIANT();
@@ -183,20 +199,16 @@
 
 	sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR);
 	sig = sleepq_catch_signals(cvp);
-	/*
-	 * XXX: Missing magic return value handling for no signal
-	 * caught but thread woken up during check.
-	 */
-	rval = sleepq_wait_sig(cvp);
+	if (sig == 0 && !TD_ON_SLEEPQ(td)) {
+		mtx_lock_spin(&sched_lock);
+		td->td_flags &= ~TDF_SINTR;
+		mtx_unlock_spin(&sched_lock);
+		sleepq_wait(cvp);
+	} else       
+		rval = sleepq_wait_sig(cvp);
 	if (rval == 0)
 		rval = sleepq_calc_signal_retval(sig);
 
-	/* XXX: Part of missing threading checks? */
-	PROC_LOCK(p);
-	if (p->p_flag & P_WEXIT)
-		rval = EINTR;
-	PROC_UNLOCK(p);
-
 #ifdef KTRACE
 	if (KTRPOINT(td, KTR_CSW))
 		ktrcsw(0, 0);
@@ -303,6 +315,24 @@
 
 	sq = sleepq_lookup(cvp);
 
+	/*
+	 * Don't bother sleeping if we are exiting and not the exiting
+	 * thread or if our thread is marked as interrupted.
+	 */
+	mtx_lock_spin(&sched_lock);
+	if (p->p_flag & P_SA || p->p_numthreads > 1) {
+		if ((p->p_flag & P_WEXIT) && p->p_singlethread != td)
+			rval = EINTR;
+		else if (td->td_flags & TDF_INTERRUPT)
+			rval = td->td_intrval;
+		if (rval != 0) {
+			mtx_unlock_spin(&sched_lock);
+			sleepq_release(cvp);
+			return (rval);
+		}
+	}
+	mtx_unlock_spin(&sched_lock);
+
 	cvp->cv_waiters++;
 	DROP_GIANT();
 	mtx_unlock(mp);
@@ -310,20 +340,16 @@
 	sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR);
 	sleepq_set_timeout(cvp, timo);
 	sig = sleepq_catch_signals(cvp);
-	/*
-	 * XXX: Missing magic return value handling for no signal
-	 * caught but thread woken up during check.
-	 */
-	rval = sleepq_timedwait_sig(cvp, sig != 0);
+	if (sig == 0 && !TD_ON_SLEEPQ(td)) {
+		mtx_lock_spin(&sched_lock);
+		td->td_flags &= ~TDF_SINTR;
+		mtx_unlock_spin(&sched_lock);
+		rval = sleepq_timedwait(cvp);
+	} else       
+		rval = sleepq_timedwait_sig(cvp, sig != 0);
 	if (rval == 0)
 		rval = sleepq_calc_signal_retval(sig);
 
-	/* XXX: Part of missing threading checks? */
-	PROC_LOCK(p);
-	if (p->p_flag & P_WEXIT)
-		rval = EINTR;
-	PROC_UNLOCK(p);
-
 #ifdef KTRACE
 	if (KTRPOINT(td, KTR_CSW))
 		ktrcsw(0, 0);

-- 
John Baldwin <jhb at FreeBSD.org>  <><  http://www.FreeBSD.org/~jhb/
"Power Users Use the Power to Serve"  =  http://www.FreeBSD.org


More information about the freebsd-threads mailing list