From 512c56af43027149e8beacf259746b8d7bf9b1a2 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 27 May 2016 22:02:54 +0200 Subject: [PATCH] common: Speedup closing fds before an exec. * common/exechelp-posix.c [__linux__]: Include dirent.h. (get_max_fds) [__linux__]: Return the actual used highest fd. -- Signed-off-by: Werner Koch --- common/exechelp-posix.c | 44 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/common/exechelp-posix.c b/common/exechelp-posix.c index 87c6e5509..81831eeb1 100644 --- a/common/exechelp-posix.c +++ b/common/exechelp-posix.c @@ -67,6 +67,11 @@ # include #endif +#if __linux__ +# include +# include +#endif /*__linux__ */ + #include "util.h" #include "i18n.h" #include "sysutils.h" @@ -97,6 +102,45 @@ get_max_fds (void) #ifdef HAVE_GETRLIMIT struct rlimit rl; + /* Under Linux we can figure out the highest used file descriptor by + * reading /proc/PID/fd. This is in the common cases much fast than + * for example doing 4096 close calls where almost all of them will + * fail. On a system with a limit of 4096 files and only 8 files + * open with the highest number being 10, we speedup close_all_fds + * from 125ms to 0.4ms including readdir. + * + * Another option would be to close the file descriptors as returned + * from reading that directory - however then we need to snapshot + * that list before starting to close them. */ +#ifdef __linux__ + { + char dirname[50]; + DIR *dir = NULL; + struct dirent *dir_entry; + const char *s; + int x; + + snprintf (dirname, sizeof dirname, "/proc/%u/fd", (unsigned int)getpid ()); + dir = opendir (dirname); + if (dir) + { + while ((dir_entry = readdir (dir))) + { + s = dir_entry->d_name; + if ( *s < '0' || *s > '9') + continue; + x = atoi (s); + if (x > max_fds) + max_fds = x; + } + closedir (dir); + } + if (max_fds != -1) + return max_fds + 1; + } +#endif /* __linux__ */ + + # ifdef RLIMIT_NOFILE if (!getrlimit (RLIMIT_NOFILE, &rl)) max_fds = rl.rlim_max;