git: 9ac6eda6c6a3 - main - pipe: try to skip locking the pipe if a non-blocking fd is used

From: Mateusz Guzik <mjg_at_FreeBSD.org>
Date: Wed, 17 Aug 2022 14:23:51 UTC
The branch main has been updated by mjg:

URL: https://cgit.FreeBSD.org/src/commit/?id=9ac6eda6c6a36db6bffa01be7faea24f8bb92a0f

commit 9ac6eda6c6a36db6bffa01be7faea24f8bb92a0f
Author:     Mateusz Guzik <mjg@FreeBSD.org>
AuthorDate: 2022-08-08 18:02:15 +0000
Commit:     Mateusz Guzik <mjg@FreeBSD.org>
CommitDate: 2022-08-17 14:23:34 +0000

    pipe: try to skip locking the pipe if a non-blocking fd is used
    
    Reviewed by:    markj (previous version)
    Differential Revision:  https://reviews.freebsd.org/D36082
---
 sys/kern/sys_pipe.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c
index d9e7d97d01e1..f9060ba2c8a6 100644
--- a/sys/kern/sys_pipe.c
+++ b/sys/kern/sys_pipe.c
@@ -721,6 +721,26 @@ pipe_read(struct file *fp, struct uio *uio, struct ucred *active_cred,
 	int size;
 
 	rpipe = fp->f_data;
+
+	/*
+	 * Try to avoid locking the pipe if we have nothing to do.
+	 *
+	 * There are programs which share one pipe amongst multiple processes
+	 * and perform non-blocking reads in parallel, even if the pipe is
+	 * empty.  This in particular is the case with BSD make, which when
+	 * spawned with a high -j number can find itself with over half of the
+	 * calls failing to find anything.
+	 */
+	if ((fp->f_flag & FNONBLOCK) != 0 && !mac_pipe_check_read_enabled()) {
+		if (__predict_false(uio->uio_resid == 0))
+			return (0);
+		if ((atomic_load_short(&rpipe->pipe_state) & PIPE_EOF) != 0)
+			return (0);
+		if (atomic_load_int(&rpipe->pipe_buffer.cnt) == 0 &&
+		    atomic_load_int(&rpipe->pipe_pages.cnt) == 0)
+			return (EAGAIN);
+	}
+
 	PIPE_LOCK(rpipe);
 	++rpipe->pipe_busy;
 	error = pipelock(rpipe, 1);