Skip to content

Commit 5e6f05c

Browse files
kolyshkinffesti
authored andcommitted
Optimize rpmSetCloseOnExec
In case maximum number of open files limit is set too high, both luaext/Pexec() and lib/doScriptExec() spend way too much time trying to set FD_CLOEXEC flag for all those file descriptors, resulting in severe increase of time it takes to execute say rpm or dnf. This becomes increasingly noticeable when running with e.g. under Docker, the reason being: > $ docker run fedora ulimit -n > 1048576 One obvious fix is to use procfs to get the actual list of opened fds and iterate over it. My quick-n-dirty benchmark shows the /proc approach is about 10x faster than iterating through a list of just 1024 fds, so it's an improvement even for default ulimit values. Note that the old method is still used in case /proc is not available. While at it, 1. fix the function by making sure we modify (rather than set) the existing flags. As the only known flag is FD_CLOEXEC, this change is currently purely aesthetical, but in case other flags will appear it will become a real bug fix. 2. get rid of magic number 3; use STDERR_FILENO Signed-off-by: Kir Kolyshkin <[email protected]> Fixes #444
1 parent 9c3e5de commit 5e6f05c

1 file changed

Lines changed: 34 additions & 9 deletions

File tree

rpmio/rpmio.c

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1760,18 +1760,43 @@ DIGEST_CTX fdDupDigest(FD_t fd, int id)
17601760
return ctx;
17611761
}
17621762

1763+
static void set_cloexec(int fd)
1764+
{
1765+
int flags = fcntl(fd, F_GETFD);
1766+
1767+
if (flags == -1 || (flags & FD_CLOEXEC))
1768+
return;
1769+
1770+
fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
1771+
}
1772+
17631773
void rpmSetCloseOnExec(void)
17641774
{
1765-
int flag, fdno, open_max;
1775+
const int min_fd = STDERR_FILENO; /* don't touch stdin/out/err */
1776+
int fd;
1777+
1778+
DIR *dir = opendir("/proc/self/fd");
1779+
if (dir == NULL) { /* /proc not available */
1780+
/* iterate over all possible fds, might be slow */
1781+
int open_max = sysconf(_SC_OPEN_MAX);
1782+
if (open_max == -1)
1783+
open_max = 1024;
17661784

1767-
open_max = sysconf(_SC_OPEN_MAX);
1768-
if (open_max == -1) {
1769-
open_max = 1024;
1785+
for (fd = min_fd + 1; fd < open_max; fd++)
1786+
set_cloexec(fd);
1787+
1788+
return;
17701789
}
1771-
for (fdno = 3; fdno < open_max; fdno++) {
1772-
flag = fcntl(fdno, F_GETFD);
1773-
if (flag == -1 || (flag & FD_CLOEXEC))
1774-
continue;
1775-
fcntl(fdno, F_SETFD, FD_CLOEXEC);
1790+
1791+
/* iterate over fds obtained from /proc */
1792+
struct dirent *entry;
1793+
while ((entry = readdir(dir)) != NULL) {
1794+
fd = atoi(entry->d_name);
1795+
if (fd > min_fd)
1796+
set_cloexec(fd);
17761797
}
1798+
1799+
closedir(dir);
1800+
1801+
return;
17771802
}

0 commit comments

Comments
 (0)