Module Name:    src
Committed By:   thorpej
Date:           Fri Oct 23 00:25:45 UTC 2020

Modified Files:
        src/sys/kern: kern_sleepq.c
        src/sys/sys: lwp.h sleepq.h

Log Message:
- sleepq_block(): Add a new LWP flag, LW_CATCHINTR, that is used to track
  the intent to catch signals while sleeping.  Initialize this flag based
  on the catch_p argument to sleepq_block(), and rather than test catch_p
  when awakened, test LW_CATCHINTR.  This allows the intent to change
  (based on whatever criteria the owner of the sleepq wishes) while the
  LWP is asleep.  This is separate from LW_SINTR in order to leave all
  other logic around LW_SINTR unaffected.
- In sleepq_transfer(), adjust also LW_CATCHINTR based on the catch_p
  argument.  Also allow the new LWP lock argument to be NULL, which
  will cause the lwp_setlock() call to be skipped; this allows transfer
  to another sleepq that is known to be protected by the same lock.
- Add a new function, sleepq_uncatch(), that will transition an LWP
  from "interruptible sleep" to "uninterruptible sleep" on its current
  sleepq.


To generate a diff of this commit:
cvs rdiff -u -r1.68 -r1.69 src/sys/kern/kern_sleepq.c
cvs rdiff -u -r1.211 -r1.212 src/sys/sys/lwp.h
cvs rdiff -u -r1.31 -r1.32 src/sys/sys/sleepq.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/kern/kern_sleepq.c
diff -u src/sys/kern/kern_sleepq.c:1.68 src/sys/kern/kern_sleepq.c:1.69
--- src/sys/kern/kern_sleepq.c:1.68	Thu May 21 00:39:04 2020
+++ src/sys/kern/kern_sleepq.c	Fri Oct 23 00:25:45 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_sleepq.c,v 1.68 2020/05/21 00:39:04 thorpej Exp $	*/
+/*	$NetBSD: kern_sleepq.c,v 1.69 2020/10/23 00:25:45 thorpej Exp $	*/
 
 /*-
  * Copyright (c) 2006, 2007, 2008, 2009, 2019, 2020 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_sleepq.c,v 1.68 2020/05/21 00:39:04 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_sleepq.c,v 1.69 2020/10/23 00:25:45 thorpej Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -267,16 +267,32 @@ sleepq_transfer(lwp_t *l, sleepq_t *from
 	l->l_wmesg = wmesg;
 
 	if (catch_p)
-		l->l_flag |= LW_SINTR;
+		l->l_flag = LW_SINTR | LW_CATCHINTR;
 	else
-		l->l_flag &= ~LW_SINTR;
+		l->l_flag = ~(LW_SINTR | LW_CATCHINTR);
 
-	lwp_setlock(l, mp);
+	/*
+	 * This allows the transfer from one sleepq to another where
+	 * it is known that they're both protected by the same lock.
+	 */
+	if (mp != NULL)
+		lwp_setlock(l, mp);
 
 	sleepq_insert(sq, l, sobj);
 }
 
 /*
+ * sleepq_uncatch:
+ *
+ *	Mark the LWP as no longer sleeping interruptibly.
+ */
+void
+sleepq_uncatch(lwp_t *l)
+{
+	l->l_flag = ~(LW_SINTR | LW_CATCHINTR);
+}
+
+/*
  * sleepq_block:
  *
  *	After any intermediate step such as releasing an interlock, switch.
@@ -299,6 +315,11 @@ sleepq_block(int timo, bool catch_p)
 	/*
 	 * If sleeping interruptably, check for pending signals, exits or
 	 * core dump events.
+	 *
+	 * Note the usage of LW_CATCHINTR.  This expresses our intent
+	 * to catch or not catch sleep interruptions, which might change
+	 * while we are sleeping.  It is independent from LW_SINTR because
+	 * we don't want to leave LW_SINTR set when the LWP is not asleep.
 	 */
 	if (catch_p) {
 		if ((l->l_flag & (LW_CANCELLED|LW_WEXIT|LW_WCORE)) != 0) {
@@ -307,7 +328,9 @@ sleepq_block(int timo, bool catch_p)
 			early = true;
 		} else if ((l->l_flag & LW_PENDSIG) != 0 && sigispending(l, 0))
 			early = true;
-	}
+		l->l_flag |= LW_CATCHINTR;
+	} else
+		l->l_flag &= ~LW_CATCHINTR;
 
 	if (early) {
 		/* lwp_unsleep() will release the lock */
@@ -342,7 +365,18 @@ sleepq_block(int timo, bool catch_p)
 		}
 	}
 
-	if (catch_p && error == 0) {
+	/*
+	 * LW_CATCHINTR is only modified in this function OR when we
+	 * are asleep (with the sleepq locked).  We can therefore safely
+	 * test it unlocked here as it is guaranteed to be stable by
+	 * virtue of us running.
+	 *
+	 * We do not bother clearing it if set; that would require us
+	 * to take the LWP lock, and it doesn't seem worth the hassle
+	 * considering it is only meaningful here inside this function,
+	 * and is set to reflect intent upon entry.
+	 */
+	if ((l->l_flag & LW_CATCHINTR) != 0 && error == 0) {
 		p = l->l_proc;
 		if ((l->l_flag & (LW_CANCELLED | LW_WEXIT | LW_WCORE)) != 0)
 			error = EINTR;

Index: src/sys/sys/lwp.h
diff -u src/sys/sys/lwp.h:1.211 src/sys/sys/lwp.h:1.212
--- src/sys/sys/lwp.h:1.211	Sat Aug  1 02:04:55 2020
+++ src/sys/sys/lwp.h	Fri Oct 23 00:25:45 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: lwp.h,v 1.211 2020/08/01 02:04:55 riastradh Exp $	*/
+/*	$NetBSD: lwp.h,v 1.212 2020/10/23 00:25:45 thorpej Exp $	*/
 
 /*
  * Copyright (c) 2001, 2006, 2007, 2008, 2009, 2010, 2019, 2020
@@ -255,6 +255,7 @@ extern int		maxlwp __read_mostly;	/* max
 #define	LW_LWPCTL	0x00000002 /* Adjust lwpctl in userret */
 #define	LW_STIMO	0x00000040 /* Sleep timed out */
 #define	LW_SINTR	0x00000080 /* Sleep is interruptible. */
+#define	LW_CATCHINTR	0x00000100 /* LW_SINTR intent; see sleepq_block(). */
 #define	LW_SYSTEM	0x00000200 /* Kernel thread */
 #define	LW_SYSTEM_FPU	0x00000400 /* Kernel thread with vector/FP enabled */
 #define	LW_DBGSUSPEND	0x00010000 /* Suspend by debugger */

Index: src/sys/sys/sleepq.h
diff -u src/sys/sys/sleepq.h:1.31 src/sys/sys/sleepq.h:1.32
--- src/sys/sys/sleepq.h:1.31	Sat May 23 20:45:11 2020
+++ src/sys/sys/sleepq.h	Fri Oct 23 00:25:45 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: sleepq.h,v 1.31 2020/05/23 20:45:11 ad Exp $	*/
+/*	$NetBSD: sleepq.h,v 1.32 2020/10/23 00:25:45 thorpej Exp $	*/
 
 /*-
  * Copyright (c) 2002, 2006, 2007, 2008, 2009, 2019, 2020
@@ -64,6 +64,7 @@ void	sleepq_enqueue(sleepq_t *, wchan_t,
 	    bool);
 void	sleepq_transfer(lwp_t *, sleepq_t *, sleepq_t *, wchan_t, const char *,
 	    struct syncobj *, kmutex_t *, bool);
+void	sleepq_uncatch(lwp_t *);
 void	sleepq_unsleep(lwp_t *, bool);
 void	sleepq_timeout(void *);
 void	sleepq_wake(sleepq_t *, wchan_t, u_int, kmutex_t *);

Reply via email to