From b5556a2c6831825fab90c03f8834d298194d8202 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Fri, 9 Jul 2021 12:40:47 +0100 Subject: [PATCH] gspawn: Use CLOSE_RANGE_CLOEXEC if available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It’s a new flag added to `close_range()` in kernel 5.11, which will allow us to speed up setting `CLOEXEC` on ranges of file descriptors. This currently happens in some situations when executing a new binary with `GSpawn`. Signed-off-by: Philip Withnall --- glib/gspawn.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/glib/gspawn.c b/glib/gspawn.c index 3073a10a4..98986d8a7 100644 --- a/glib/gspawn.c +++ b/glib/gspawn.c @@ -1482,6 +1482,28 @@ safe_fdwalk (int (*cb)(void *data, int fd), void *data) #endif } +/* This function is called between fork() and exec() and hence must be + * async-signal-safe (see signal-safety(7)). */ +static void +safe_fdwalk_set_cloexec (int lowfd) +{ +#if defined(HAVE_CLOSE_RANGE) && defined(CLOSE_RANGE_CLOEXEC) + /* close_range() is available in Linux since kernel 5.9, and on FreeBSD at + * around the same time. It was designed for use in async-signal-safe + * situations: https://bugs.python.org/issue38061 + * + * The `CLOSE_RANGE_CLOEXEC` flag was added in Linux 5.11, and is not yet + * present in FreeBSD. + * + * Handle ENOSYS in case it’s supported in libc but not the kernel; if so, + * fall back to safe_fdwalk(). Handle EINVAL in case `CLOSE_RANGE_CLOEXEC` + * is not supported. */ + if (close_range (lowfd, G_MAXUINT, CLOSE_RANGE_CLOEXEC) != 0 && + (errno == ENOSYS || errno == EINVAL)) +#endif /* HAVE_CLOSE_RANGE */ + (void) safe_fdwalk (set_cloexec, GINT_TO_POINTER (lowfd)); +} + /* This function is called between fork() and exec() and hence must be * async-signal-safe (see signal-safety(7)). */ static void @@ -1689,7 +1711,7 @@ do_exec (gint child_err_report_fd, } else { - safe_fdwalk (set_cloexec, GINT_TO_POINTER (3)); + safe_fdwalk_set_cloexec (3); } } else