Skip to content

Commit 2eda646

Browse files
committed
Processing (Linux): use posix_spawnp for better performance
1 parent 2622fc1 commit 2eda646

1 file changed

Lines changed: 49 additions & 23 deletions

File tree

src/common/processing_linux.c

Lines changed: 49 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <fcntl.h>
1212
#include <errno.h>
1313
#include <sys/wait.h>
14+
#include <spawn.h>
1415

1516
#if defined(__FreeBSD__) || defined(__APPLE__)
1617
#include <sys/types.h>
@@ -33,6 +34,10 @@
3334
#include <image.h>
3435
#endif
3536

37+
#ifndef environ
38+
extern char** environ;
39+
#endif
40+
3641
enum { FF_PIPE_BUFSIZ = 8192 };
3742

3843
static inline int ffPipe2(int* fds, int flags)
@@ -56,27 +61,38 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
5661
if(ffPipe2(pipes, O_CLOEXEC) == -1)
5762
return "pipe() failed";
5863

59-
pid_t childPid = fork();
60-
if(childPid == -1)
61-
{
62-
close(pipes[0]);
63-
close(pipes[1]);
64-
return "fork() failed";
65-
}
64+
posix_spawn_file_actions_t file_actions;
65+
posix_spawn_file_actions_init(&file_actions);
66+
posix_spawn_file_actions_adddup2(&file_actions, pipes[1], useStdErr ? STDERR_FILENO : STDOUT_FILENO);
67+
posix_spawn_file_actions_addopen(&file_actions, useStdErr ? STDOUT_FILENO : STDERR_FILENO, "/dev/null", O_WRONLY, 0);
68+
pid_t childPid = -1;
6669

67-
//Child
68-
if(childPid == 0)
70+
char* oldLang = NULL;
71+
int langIndex = -1;
72+
for (int i = 0; environ[i] != NULL; i++)
6973
{
70-
int nullFile = open("/dev/null", O_WRONLY | O_CLOEXEC);
71-
dup2(pipes[1], useStdErr ? STDERR_FILENO : STDOUT_FILENO);
72-
dup2(nullFile, useStdErr ? STDOUT_FILENO : STDERR_FILENO);
73-
setenv("LANG", "C", 1);
74-
execvp(argv[0], argv);
75-
_exit(127);
74+
if (ffStrStartsWith(environ[i], "LANG="))
75+
{
76+
oldLang = environ[i];
77+
environ[i] = (char*) "LANG=C";
78+
langIndex = i;
79+
break;
80+
}
7681
}
7782

78-
//Parent
83+
int ret = posix_spawnp(&childPid, argv[0], &file_actions, NULL, argv, environ);
84+
85+
if (oldLang)
86+
environ[langIndex] = oldLang;
87+
88+
posix_spawn_file_actions_destroy(&file_actions);
89+
7990
close(pipes[1]);
91+
if (ret != 0)
92+
{
93+
close(pipes[0]);
94+
return "posix_spawnp() failed";
95+
}
8096

8197
int FF_AUTO_CLOSE_FD childPipeFd = pipes[0];
8298
char str[FF_PIPE_BUFSIZ];
@@ -86,20 +102,30 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
86102
if (timeout >= 0)
87103
{
88104
struct pollfd pollfd = { childPipeFd, POLLIN, 0 };
89-
if (poll(&pollfd, 1, timeout) == 0)
105+
int pollret = poll(&pollfd, 1, timeout);
106+
if (pollret == 0)
90107
{
91108
kill(childPid, SIGTERM);
92109
waitpid(childPid, NULL, 0);
93110
return "poll(&pollfd, 1, timeout) timeout (try increasing --processing-timeout)";
94111
}
95-
else if (errno == EINTR)
112+
else if (pollret < 0)
96113
{
97-
// The child process has been terminated. See `chldSignalHandler` in `common/init.c`
98-
if (waitpid(childPid, NULL, WNOHANG) == childPid)
114+
if (errno == EINTR)
115+
{
116+
// The child process has been terminated. See `chldSignalHandler` in `common/init.c`
117+
if (waitpid(childPid, NULL, WNOHANG) == childPid)
118+
{
119+
// Read remaining data from the pipe
120+
fcntl(childPipeFd, F_SETFL, O_CLOEXEC | O_NONBLOCK);
121+
childPid = -1;
122+
}
123+
}
124+
else
99125
{
100-
// Read remaining data from the pipe
101-
fcntl(childPipeFd, F_SETFL, O_CLOEXEC | O_NONBLOCK);
102-
childPid = -1;
126+
kill(childPid, SIGTERM);
127+
waitpid(childPid, NULL, 0);
128+
return "poll(&pollfd, 1, timeout) error";
103129
}
104130
}
105131
else if (pollfd.revents & POLLERR)

0 commit comments

Comments
 (0)