diff options
author | Andrew Whatson <whatson@gmail.com> | 2022-12-23 00:27:22 +0100 |
---|---|---|
committer | Ludovic Courtès <ludo@gnu.org> | 2023-01-13 16:07:42 +0100 |
commit | 9332b632407894c2e1951cce1bc678f19e1fa8e4 (patch) | |
tree | 0a4a8907e89f90b696d3a02867970c25ad340087 /libguile | |
parent | 527c257d6e0ad0480a859f69e9dcf3b0c7aad76e (diff) | |
download | guile-9332b632407894c2e1951cce1bc678f19e1fa8e4.tar.gz |
Reduce redundant 'close' calls when forking on some systems.
Fixes <https://bugs.gnu.org/59321>.
Reported by <hylophile@posteo.de>.
Some systems provide "/proc/self/fd" which is a directory containing an
entry for each open file descriptor in the current process. We use this
to limit the number of close() calls needed to ensure file descriptors
aren't leaked to the child process when forking.
* libguile/posix.c (close_inherited_fds_slow):
(close_inherited_fds): New static helper functions.
(scm_spawn_process): Attempt to close inherited file descriptors
efficiently using 'close_inherited_fds', falling back to the brute-force
approach in 'close_inherited_fds_slow'.
* NEWS: Update.
Diffstat (limited to 'libguile')
-rw-r--r-- | libguile/posix.c | 41 |
1 files changed, 38 insertions, 3 deletions
diff --git a/libguile/posix.c b/libguile/posix.c index 8d1981c20..ae9792890 100644 --- a/libguile/posix.c +++ b/libguile/posix.c @@ -24,6 +24,7 @@ # include <config.h> #endif +#include <dirent.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> @@ -1317,6 +1318,41 @@ SCM_DEFINE (scm_fork, "primitive-fork", 0, 0, 0, #undef FUNC_NAME #endif /* HAVE_FORK */ +static void +close_inherited_fds_slow (posix_spawn_file_actions_t *actions, int max_fd) +{ + while (--max_fd > 2) + posix_spawn_file_actions_addclose (actions, max_fd); +} + +static void +close_inherited_fds (posix_spawn_file_actions_t *actions, int max_fd) +{ + DIR *dirp; + struct dirent *d; + int fd; + + /* Try to use the platform-specific list of open file descriptors, so + we don't need to use the brute force approach. */ + dirp = opendir ("/proc/self/fd"); + + if (dirp == NULL) + return close_inherited_fds_slow (actions, max_fd); + + while ((d = readdir (dirp)) != NULL) + { + fd = atoi (d->d_name); + + /* Skip "." and "..", garbage entries, stdin/stdout/stderr. */ + if (fd <= 2) + continue; + + posix_spawn_file_actions_addclose (actions, fd); + } + + closedir (dirp); +} + static pid_t do_spawn (char *exec_file, char **exec_argv, char **exec_env, int in, int out, int err, int spawnp) @@ -1341,7 +1377,7 @@ do_spawn (char *exec_file, char **exec_argv, char **exec_env, int free_fd_slots = 0; int fd_slot[3]; - for (int fdnum = 3;free_fd_slots < 3 && fdnum < max_fd;fdnum++) + for (int fdnum = 3; free_fd_slots < 3 && fdnum < max_fd; fdnum++) { if (fdnum != in && fdnum != out && fdnum != err) { @@ -1360,8 +1396,7 @@ do_spawn (char *exec_file, char **exec_argv, char **exec_env, posix_spawn_file_actions_adddup2 (&actions, fd_slot[1], 1); posix_spawn_file_actions_adddup2 (&actions, fd_slot[2], 2); - while (--max_fd > 2) - posix_spawn_file_actions_addclose (&actions, max_fd); + close_inherited_fds (&actions, max_fd); int res = -1; if (spawnp) |