Module Name: src Committed By: dholland Date: Mon Jan 25 19:21:11 UTC 2021
Modified Files: src/sys/kern: sys_pipe.c src/sys/sys: pipe.h Log Message: Fix a thundering herd problem in pipes. Wake only one waiter when data becomes available, not all of them. Waking them all is not a usual case, but turns up with make's job token pipes. (Probably make's job signalling scheme should also be revised, assuming rillig hasn't already done that, but that's a separate issue.) This change will not do us much good for the moment because we don't distinguish cv_signal from cv_broadcast for interruptible sleeps, but that's also a separate problem. Seen on FreeBSD; from mjg at freebsd a couple months ago. Patch was mine (iirc) but the real work in this sort of thing is discovering the problem. To generate a diff of this commit: cvs rdiff -u -r1.151 -r1.152 src/sys/kern/sys_pipe.c cvs rdiff -u -r1.37 -r1.38 src/sys/sys/pipe.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/sys_pipe.c diff -u src/sys/kern/sys_pipe.c:1.151 src/sys/kern/sys_pipe.c:1.152 --- src/sys/kern/sys_pipe.c:1.151 Fri Dec 11 03:00:09 2020 +++ src/sys/kern/sys_pipe.c Mon Jan 25 19:21:11 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: sys_pipe.c,v 1.151 2020/12/11 03:00:09 thorpej Exp $ */ +/* $NetBSD: sys_pipe.c,v 1.152 2021/01/25 19:21:11 dholland Exp $ */ /*- * Copyright (c) 2003, 2007, 2008, 2009 The NetBSD Foundation, Inc. @@ -68,7 +68,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sys_pipe.c,v 1.151 2020/12/11 03:00:09 thorpej Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sys_pipe.c,v 1.152 2021/01/25 19:21:11 dholland Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -344,13 +344,19 @@ pipelock(struct pipe *pipe, bool catch_p KASSERT(mutex_owned(pipe->pipe_lock)); while (pipe->pipe_state & PIPE_LOCKFL) { - pipe->pipe_state |= PIPE_LWANT; + pipe->pipe_waiters++; + KASSERT(pipe->pipe_waiters != 0); /* just in case */ if (catch_p) { error = cv_wait_sig(&pipe->pipe_lkcv, pipe->pipe_lock); - if (error != 0) + if (error != 0) { + KASSERT(pipe->pipe_waiters > 0); + pipe->pipe_waiters--; return error; + } } else cv_wait(&pipe->pipe_lkcv, pipe->pipe_lock); + KASSERT(pipe->pipe_waiters > 0); + pipe->pipe_waiters--; } pipe->pipe_state |= PIPE_LOCKFL; @@ -368,9 +374,8 @@ pipeunlock(struct pipe *pipe) KASSERT(pipe->pipe_state & PIPE_LOCKFL); pipe->pipe_state &= ~PIPE_LOCKFL; - if (pipe->pipe_state & PIPE_LWANT) { - pipe->pipe_state &= ~PIPE_LWANT; - cv_broadcast(&pipe->pipe_lkcv); + if (pipe->pipe_waiters > 0) { + cv_signal(&pipe->pipe_lkcv); } } Index: src/sys/sys/pipe.h diff -u src/sys/sys/pipe.h:1.37 src/sys/sys/pipe.h:1.38 --- src/sys/sys/pipe.h:1.37 Thu Jun 25 14:22:19 2020 +++ src/sys/sys/pipe.h Mon Jan 25 19:21:11 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: pipe.h,v 1.37 2020/06/25 14:22:19 jdolecek Exp $ */ +/* $NetBSD: pipe.h,v 1.38 2021/01/25 19:21:11 dholland Exp $ */ /* * Copyright (c) 1996 John S. Dyson @@ -80,8 +80,7 @@ struct pipebuf { #define PIPE_SIGNALR 0x020 /* Do selwakeup() on read(2) */ #define PIPE_LOCKFL 0x100 /* Process has exclusive access to pointers/data. */ -#define PIPE_LWANT 0x200 /* Process wants exclusive access to - pointers/data. */ +/* unused 0x200 */ #define PIPE_RESTART 0x400 /* Return ERESTART to blocked syscalls */ /* @@ -100,6 +99,7 @@ struct pipe { struct timespec pipe_mtime; /* time of last modify */ struct timespec pipe_btime; /* time of creation */ pid_t pipe_pgid; /* process group for sigio */ + u_int pipe_waiters; /* number of waiters pending */ struct pipe *pipe_peer; /* link with other direction */ u_int pipe_state; /* pipe status info */ int pipe_busy; /* busy flag, to handle rundown */