gspawn: Don’t use getrlimit() or sysconf() in async-signal-safe context

They’re not safe to call in an async-signal-safe context on Linux.
`sysconf()` is safe to call on FreeBSD and OpenBSD (at least), so
continue doing that.

This will reduce performance in the (already low performance) fallback
case where `/proc` is inaccessible to a forked process on Linux, while
spawning a subprocess.

See `man 7 signal-safety`.

Signed-off-by: Philip Withnall <withnall@endlessm.com>

Helps: #2140
This commit is contained in:
Philip Withnall 2020-06-22 13:40:27 +01:00
parent 1051bfe11e
commit 84f188ae24

View File

@ -1218,11 +1218,11 @@ safe_fdwalk (int (*cb)(void *data, int fd), void *data)
* may be slow on non-Linux operating systems, especially on systems allowing
* very high number of open file descriptors.
*/
gint open_max;
gint open_max = -1;
gint fd;
gint res = 0;
#ifdef HAVE_SYS_RESOURCE_H
#if 0 && defined(HAVE_SYS_RESOURCE_H)
struct rlimit rl;
#endif
@ -1255,19 +1255,36 @@ safe_fdwalk (int (*cb)(void *data, int fd), void *data)
}
/* If /proc is not mounted or not accessible we fall back to the old
* rlimit trick.
* rlimit trick. */
#endif
#if 0 && defined(HAVE_SYS_RESOURCE_H)
/* Use getrlimit() function provided by the system if it is known to be
* async-signal safe.
*
* FIXME: getrlimit() and sysconf() are not async-signal-safe. */
#endif
#ifdef HAVE_SYS_RESOURCE_H
if (getrlimit(RLIMIT_NOFILE, &rl) == 0 && rl.rlim_max != RLIM_INFINITY)
* Currently there are no operating systems known to provide a safe
* implementation, so this section is not used for now.
*/
if (getrlimit (RLIMIT_NOFILE, &rl) == 0 && rl.rlim_max != RLIM_INFINITY)
open_max = rl.rlim_max;
else
#endif
#if defined(__FreeBSD__) || defined(__OpenBSD__)
/* Use sysconf() function provided by the system if it is known to be
* async-signal safe.
*
* FreeBSD: sysconf() is included in the list of async-signal safe functions
* found in https://man.freebsd.org/sigaction(2).
*
* OpenBSD: sysconf() is included in the list of async-signal safe functions
* found in https://man.openbsd.org/sigaction.2.
*/
if (open_max < 0)
open_max = sysconf (_SC_OPEN_MAX);
#endif
/* Hardcoded fallback: the default process hard limit in Linux as of 2020 */
if (open_max < 0)
open_max = 4096;
for (fd = 0; fd < open_max; fd++)
if ((res = cb (data, fd)) != 0)