gspawn: Use CLOSE_RANGE_CLOEXEC if available

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 <pwithnall@endlessos.org>
This commit is contained in:
Philip Withnall 2021-07-09 12:40:47 +01:00
parent cfe8a0bd75
commit b5556a2c68

View File

@ -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 its 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