commit c012d7b0d5248a99a3a92780687a676c5d420f5f Author: Andrew Whatson Date: Thu Dec 8 21:43:28 2022 +1000 Reduce redundant close() calls when forking on some systems. 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'. diff --git a/libguile/posix.c b/libguile/posix.c index 87b329da9..8c9022116 100644 --- a/libguile/posix.c +++ b/libguile/posix.c @@ -24,6 +24,7 @@ # include #endif +#include #include #include #include @@ -1309,6 +1310,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 SCM scm_spawn_process (SCM prog, SCM args, SCM scm_in, SCM scm_out, SCM scm_err) #define FUNC_NAME "spawn*" @@ -1363,8 +1399,7 @@ scm_spawn_process (SCM prog, SCM args, SCM scm_in, SCM scm_out, SCM scm_err) 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); if (posix_spawnp (&pid, exec_file, &actions, attrp, exec_argv, environ) != 0) {