summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Whatson <whatson@gmail.com>2022-12-23 00:27:22 +0100
committerLudovic Courtès <ludo@gnu.org>2023-01-13 16:07:42 +0100
commit9332b632407894c2e1951cce1bc678f19e1fa8e4 (patch)
tree0a4a8907e89f90b696d3a02867970c25ad340087
parent527c257d6e0ad0480a859f69e9dcf3b0c7aad76e (diff)
downloadguile-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.
-rw-r--r--NEWS2
-rw-r--r--libguile/posix.c41
2 files changed, 40 insertions, 3 deletions
diff --git a/NEWS b/NEWS
index f1c53efe7..121ad0b8e 100644
--- a/NEWS
+++ b/NEWS
@@ -99,6 +99,8 @@ Disassembler output now includes the name of intrinsics next to each
mode was set explicitly. However, this is not the case.
** 'system*' honors output/error port redirects
(https://bugs.gnu.org/52835)
+** 'open-input-pipe' & co. are now much faster
+ (https://bugs.gnu.org/59321)
Changes in 3.0.8 (since 3.0.7)
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)