Skip to content

Commit 48089bd

Browse files
committed
TraceScreen: fix unnecessary copying parent memory page table
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 8211b10 commit 48089bd

1 file changed

Lines changed: 28 additions & 33 deletions

File tree

TraceScreen.c

Lines changed: 28 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ in the source distribution for its full text.
1313
#include <errno.h>
1414
#include <fcntl.h>
1515
#include <signal.h>
16+
#include <spawn.h>
1617
#include <stdbool.h>
1718
#include <stdio.h>
1819
#include <stdlib.h>
@@ -78,42 +79,36 @@ bool TraceScreen_forkTracer(TraceScreen* this) {
7879
if (fcntl(fdpair[1], F_SETFL, O_NONBLOCK) < 0)
7980
goto err;
8081

81-
pid_t child = fork();
82-
if (child == -1)
82+
pid_t child;
83+
posix_spawnattr_t attr;
84+
posix_spawnattr_init(&attr);
85+
posix_spawn_file_actions_t fa;
86+
posix_spawn_file_actions_init(&fa);
87+
posix_spawn_file_actions_addclose(&fa, fdpair[0]);
88+
posix_spawn_file_actions_adddup2(&fa, fdpair[1], STDOUT_FILENO);
89+
posix_spawn_file_actions_adddup2(&fa, fdpair[1], STDERR_FILENO);
90+
posix_spawn_file_actions_addclose(&fa, fdpair[1]);
91+
92+
char buffer[32] = {0};
93+
xSnprintf(buffer, sizeof(buffer), "%d", Process_getPid(this->super.process));
94+
95+
#if defined(HTOP_FREEBSD) || defined(HTOP_OPENBSD) || defined(HTOP_NETBSD) || defined(HTOP_DRAGONFLYBSD) || defined(HTOP_SOLARIS)
96+
char* const args[] = { (char*)"truss", (char*)"-s", (char*)"512", (char*)"-p", buffer, NULL };
97+
#elif defined(HTOP_LINUX)
98+
char* const args[] = { (char*)"strace", (char*)"-T", (char*)"-tt", (char*)"-s", (char*)"512", (char*)"-p", buffer, NULL };
99+
#else
100+
char* const args[] = { NULL };
101+
#endif
102+
103+
if (!args[0] || posix_spawn(&child, args[0], &fa, &attr, args, NULL) != 0) {
104+
posix_spawnattr_destroy(&attr);
105+
posix_spawn_file_actions_destroy(&fa);
83106
goto err;
84-
85-
if (child == 0) {
86-
close(fdpair[0]);
87-
88-
dup2(fdpair[1], STDOUT_FILENO);
89-
dup2(fdpair[1], STDERR_FILENO);
90-
close(fdpair[1]);
91-
92-
char buffer[32] = {0};
93-
xSnprintf(buffer, sizeof(buffer), "%d", Process_getPid(this->super.process));
94-
95-
#if defined(HTOP_FREEBSD) || defined(HTOP_OPENBSD) || defined(HTOP_NETBSD) || defined(HTOP_DRAGONFLYBSD) || defined(HTOP_SOLARIS)
96-
// Use of NULL in variadic functions must have a pointer cast.
97-
// The NULL constant is not required by standard to have a pointer type.
98-
execlp("truss", "truss", "-s", "512", "-p", buffer, (void*)NULL);
99-
100-
// Should never reach here, unless execlp fails ...
101-
const char* message = "Could not execute 'truss'. Please make sure it is available in your $PATH.";
102-
(void)! write(STDERR_FILENO, message, strlen(message));
103-
#elif defined(HTOP_LINUX)
104-
execlp("strace", "strace", "-T", "-tt", "-s", "512", "-p", buffer, (void*)NULL);
105-
106-
// Should never reach here, unless execlp fails ...
107-
const char* message = "Could not execute 'strace'. Please make sure it is available in your $PATH.";
108-
(void)! write(STDERR_FILENO, message, strlen(message));
109-
#else // HTOP_DARWIN, HTOP_PCP == HTOP_UNSUPPORTED
110-
const char* message = "Tracing unavailable on not supported system.";
111-
(void)! write(STDERR_FILENO, message, strlen(message));
112-
#endif
113-
114-
exit(127);
115107
}
116108

109+
posix_spawnattr_destroy(&attr);
110+
posix_spawn_file_actions_destroy(&fa);
111+
117112
FILE* fp = fdopen(fdpair[0], "r");
118113
if (!fp)
119114
goto err;

0 commit comments

Comments
 (0)