From 26c944125bde337329180b65d3c12fa89c413d77 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Tue, 12 Jan 2021 17:32:28 +0100 Subject: [PATCH] Close FDs based on /proc/self/fd ... not to waste time with close(2)ing RLIMIT_NOFILE-3 non-existing FDs. Newer kernel = higher RLIMIT_NOFILE = more time wasted refs #8437 --- icinga-app/icinga.cpp | 19 +++----------- lib/base/process.cpp | 12 +-------- lib/base/utility.cpp | 61 +++++++++++++++++++++++++++++++++++++++++-- lib/base/utility.hpp | 3 +++ 4 files changed, 67 insertions(+), 28 deletions(-) diff --git a/icinga-app/icinga.cpp b/icinga-app/icinga.cpp index 7aef1ca03..05f4944f6 100644 --- a/icinga-app/icinga.cpp +++ b/icinga-app/icinga.cpp @@ -906,24 +906,13 @@ int main(int argc, char **argv) #ifndef _WIN32 String keepFDs = Utility::GetFromEnvironment("ICINGA2_KEEP_FDS"); if (keepFDs.IsEmpty()) { - rlimit rl; - if (getrlimit(RLIMIT_NOFILE, &rl) >= 0) { - rlim_t maxfds = rl.rlim_max; - - if (maxfds == RLIM_INFINITY) - maxfds = 65536; - - for (rlim_t i = 3; i < maxfds; i++) { - int rc = close(i); - #ifdef I2_DEBUG - if (rc >= 0) - std::cerr << "Closed FD " << i << " which we inherited from our parent process." << std::endl; + Utility::CloseAllFDs({0, 1, 2}, [](int fd) { + std::cerr << "Closed FD " << fd << " which we inherited from our parent process." << std::endl; + }); #else /* I2_DEBUG */ - (void)rc; + Utility::CloseAllFDs({0, 1, 2}); #endif /* I2_DEBUG */ - } - } } #endif /* _WIN32 */ diff --git a/lib/base/process.cpp b/lib/base/process.cpp index c16eaa7c1..16106d21d 100644 --- a/lib/base/process.cpp +++ b/lib/base/process.cpp @@ -240,17 +240,7 @@ static void ProcessHandler() sigfillset(&mask); sigprocmask(SIG_SETMASK, &mask, nullptr); - rlimit rl; - if (getrlimit(RLIMIT_NOFILE, &rl) >= 0) { - rlim_t maxfds = rl.rlim_max; - - if (maxfds == RLIM_INFINITY) - maxfds = 65536; - - for (rlim_t i = 3; i < maxfds; i++) - if (i != static_cast(l_ProcessControlFD)) - (void)close(i); - } + Utility::CloseAllFDs({0, 1, 2, l_ProcessControlFD}); for (;;) { size_t length; diff --git a/lib/base/utility.cpp b/lib/base/utility.cpp index d8e6f20b0..1c3ec0a9c 100644 --- a/lib/base/utility.cpp +++ b/lib/base/utility.cpp @@ -9,10 +9,10 @@ #include "base/utility.hpp" #include "base/json.hpp" #include "base/objectlock.hpp" +#include #include #include -#include -#include +#include #include #include #include @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -44,6 +45,7 @@ # include # include # include +# include #endif /* _WIN32 */ #ifdef _WIN32 @@ -833,6 +835,61 @@ void Utility::SetCloExec(int fd, bool cloexec) << boost::errinfo_errno(errno)); } } + +void Utility::CloseAllFDs(const std::vector& except, std::function onClose) +{ +#if defined(__linux__) || defined(__APPLE__) + namespace fs = boost::filesystem; + + std::set fds; + +#ifdef __linux__ + const char *dir = "/proc/self/fd"; +#endif /* __linux__ */ +#ifdef __APPLE__ + const char *dir = "/dev/fd"; +#endif /* __APPLE__ */ + + for (fs::directory_iterator current {fs::path(dir)}, end; current != end; ++current) { + auto entry (current->path().filename()); + int fd; + + try { + fd = boost::lexical_cast(entry.c_str()); + } catch (...) { + continue; + } + + fds.emplace(fd); + } + + for (auto fd : except) { + fds.erase(fd); + } + + for (auto fd : fds) { + if (close(fd) >= 0 && onClose) { + onClose(fd); + } + } +#else /* __linux__ || __APPLE__ */ + rlimit rl; + + if (getrlimit(RLIMIT_NOFILE, &rl) >= 0) { + rlim_t maxfds = rl.rlim_max; + + if (maxfds == RLIM_INFINITY) { + maxfds = 65536; + } + + for (int fd = 0; fd < maxfds; ++fd) { + if (std::find(except.begin(), except.end(), fd) == except.end() && close(fd) >= 0 && onClose) { + onClose(fd); + } + } + } +#endif /* __linux__ || __APPLE__ */ +} #endif /* _WIN32 */ void Utility::SetNonBlockingSocket(SOCKET s, bool nb) diff --git a/lib/base/utility.hpp b/lib/base/utility.hpp index 676016089..0fb216d9e 100644 --- a/lib/base/utility.hpp +++ b/lib/base/utility.hpp @@ -8,6 +8,7 @@ #include "base/array.hpp" #include "base/threadpool.hpp" #include +#include #include #include @@ -80,6 +81,8 @@ public: #ifndef _WIN32 static void SetNonBlocking(int fd, bool nb = true); static void SetCloExec(int fd, bool cloexec = true); + + static void CloseAllFDs(const std::vector& except, std::function onClose = nullptr); #endif /* _WIN32 */ static void SetNonBlockingSocket(SOCKET s, bool nb = true);