Blob Blame History Raw
From 8a5bf2ad16c416c389147ca59c56545e038470e1 Mon Sep 17 00:00:00 2001
From: John Eckersberg <jeckersb@redhat.com>
Date: Fri, 11 Oct 2019 13:06:20 -0400
Subject: [PATCH] erl_child_setup: reduce number of calls to close()

On systems without closefrom(), such as Linux, iterating over all
possible file descriptors and calling close() for each is inefficient.
This is markedly so when the maximum number of file descriptors has
been tuned to a large number.

Instead, walk the open descriptors under /dev/fd and close only those
which are open.
---
 erts/emulator/sys/unix/erl_child_setup.c | 25 +++++++++++++++++++++---
 1 file changed, 22 insertions(+), 3 deletions(-)

diff --git a/erts/emulator/sys/unix/erl_child_setup.c b/erts/emulator/sys/unix/erl_child_setup.c
index 129861ebd5..7ddd753136 100644
--- a/erts/emulator/sys/unix/erl_child_setup.c
+++ b/erts/emulator/sys/unix/erl_child_setup.c
@@ -411,6 +411,7 @@ main(int argc, char *argv[])
     int uds_fd = 3, max_fd = 3;
 #ifndef HAVE_CLOSEFROM
     int i;
+    DIR *dir;
 #endif
     struct sigaction sa;
 
@@ -426,11 +427,29 @@ main(int argc, char *argv[])
 #if defined(HAVE_CLOSEFROM)
     closefrom(4);
 #else
-    for (i = 4; i < max_files; i++)
+    dir = opendir("/dev/fd");
+    if (dir == NULL) { /* /dev/fd not available */
+        for (i = 4; i < max_files; i++)
 #if defined(__ANDROID__)
-        if (i != system_properties_fd())
+            if (i != system_properties_fd())
 #endif
-        (void) close(i);
+            (void) close(i);
+    } else {
+        /* Iterate over fds obtained from /dev/fd */
+        struct dirent *entry;
+        int dir_fd = dirfd(dir);
+
+        while ((entry = readdir(dir)) != NULL) {
+            i = atoi(entry->d_name);
+#if defined(__ANDROID__)
+            if (i != system_properties_fd())
+#endif
+            if (i >= 4 && i != dir_fd)
+                (void) close(i);
+        }
+
+        closedir(dir);
+    }
 #endif
 
     if (pipe(sigchld_pipe) < 0) {
-- 
2.23.0