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 *);