Skip to content

Commit e1d4413

Browse files
committed
librc: continue migrate popen() to posix_spawn()
Added execute_get_output() new function has been created that reads commands and replaces two popen() calls. posix_spawn() is a more lightweight and modern alternative to fork()/exec(), which are used inside popen(). The main advantage of posix_spawn is that it can create a new process without completely duplicating the address space of the parent process. References: - https://blog.famzah.net/2018/12/19/posix_spawn-performance-benchmarks-and-usage-examples/ - https://lobste.rs/s/smbsd5/fork_road - https://www.reddit.com/r/C_Programming/comments/1lvdhp2/fork_vs_posix_spawn/
1 parent 584444d commit e1d4413

File tree

1 file changed

+59
-18
lines changed

1 file changed

+59
-18
lines changed

src/librc/librc.c

Lines changed: 59 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
#include <sys/param.h>
3232
#include <sys/stat.h>
3333
#include <unistd.h>
34+
#include <spawn.h>
35+
#include <sys/wait.h>
3436

3537
#include "queue.h"
3638
#include "librc.h"
@@ -174,6 +176,60 @@ rm_dir(int targetfd, const char *pathname, bool top)
174176
return true;
175177
}
176178

179+
/*
180+
* Execute a command and returns its output.
181+
* The caller is responsible for freeing the returned string.
182+
*/
183+
static char *
184+
execute_get_output(const char *command)
185+
{
186+
posix_spawn_file_actions_t action;
187+
int out[2];
188+
char *line = NULL;
189+
size_t len = 0;
190+
pid_t pid;
191+
FILE *fp;
192+
char *const args[] = {
193+
(char *)"sh",
194+
(char *)"-c",
195+
(char *)command,
196+
NULL
197+
};
198+
199+
if (pipe(out) != 0)
200+
return NULL;
201+
202+
if (posix_spawn_file_actions_init(&action) != 0) {
203+
close(out[0]);
204+
close(out[1]);
205+
return NULL;
206+
}
207+
posix_spawn_file_actions_addclose(&action, out[0]);
208+
posix_spawn_file_actions_adddup2(&action, out[1], STDOUT_FILENO);
209+
posix_spawn_file_actions_addclose(&action, out[1]);
210+
211+
if (posix_spawnp(&pid, "sh", &action, NULL, args, NULL) != 0) {
212+
posix_spawn_file_actions_destroy(&action);
213+
close(out[0]);
214+
close(out[1]);
215+
return NULL;
216+
}
217+
posix_spawn_file_actions_destroy(&action);
218+
close(out[1]);
219+
220+
if ((fp = fdopen(out[0], "r"))) {
221+
if (xgetline(&line, &len, fp) == -1) {
222+
free(line);
223+
line = NULL;
224+
}
225+
fclose(fp);
226+
} else
227+
close(out[0]);
228+
229+
waitpid(pid, NULL, 0);
230+
return line;
231+
}
232+
177233
/* Other systems may need this at some point, but for now it's Linux only */
178234
#ifdef __linux__
179235
static bool
@@ -891,24 +947,18 @@ rc_service_extra_commands(const char *service)
891947
char *svc;
892948
char *cmd = NULL;
893949
char *buffer = NULL;
894-
size_t len = 0;
895950
RC_STRINGLIST *commands = NULL;
896951
char *token;
897952
char *p;
898-
FILE *fp;
899953

900954
if (!(svc = rc_service_resolve(service)))
901955
return NULL;
902956

903957
xasprintf(&cmd, OPTSTR, svc);
904958
free(svc);
905959

906-
if (!(fp = popen(cmd, "r"))) {
907-
free(cmd);
908-
return NULL;
909-
}
910-
911-
if (xgetline(&buffer, &len, fp) != -1) {
960+
buffer = execute_get_output(cmd);
961+
if (buffer) {
912962
p = buffer;
913963
commands = rc_stringlist_new();
914964

@@ -917,7 +967,6 @@ rc_service_extra_commands(const char *service)
917967
rc_stringlist_add(commands, token);
918968
}
919969

920-
pclose(fp);
921970
free(buffer);
922971
free(cmd);
923972
return commands;
@@ -930,8 +979,6 @@ rc_service_description(const char *service, const char *option)
930979
char *svc;
931980
char *cmd;
932981
char *desc = NULL;
933-
size_t size = 0;
934-
FILE *fp;
935982

936983
if (!(svc = rc_service_resolve(service)))
937984
return NULL;
@@ -941,13 +988,7 @@ rc_service_description(const char *service, const char *option)
941988

942989
xasprintf(&cmd, DESCSTR, svc, *option ? "_" : "", option);
943990
free(svc);
944-
if ((fp = popen(cmd, "r"))) {
945-
if (xgetline(&desc, &size, fp) == -1) {
946-
free(desc);
947-
desc = NULL;
948-
}
949-
pclose(fp);
950-
}
991+
desc = execute_get_output(cmd);
951992
free(cmd);
952993
return desc;
953994
}

0 commit comments

Comments
 (0)