mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-03-15 05:33:58 -04:00
slave: use an event FD to communicate errors after fork before exec
Replace the pipe we used to communicate errors after fork(), but before exec() to the parent process with an event FD. The overhead in the kernel is much lower to setup an event fd, compared to a pipe.
This commit is contained in:
parent
c8e78674ed
commit
027a8de6f5
1 changed files with 17 additions and 20 deletions
37
slave.c
37
slave.c
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/eventfd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
#define LOG_MODULE "slave"
|
#define LOG_MODULE "slave"
|
||||||
|
|
@ -231,7 +232,7 @@ slave_exec(int ptmx, char *argv[], int err_fd, bool login_shell,
|
||||||
execvp(file, argv);
|
execvp(file, argv);
|
||||||
|
|
||||||
err:
|
err:
|
||||||
(void)!write(err_fd, &errno, sizeof(errno));
|
(void)!write(err_fd, &(uint64_t){errno}, sizeof(uint64_t));
|
||||||
if (pts != -1)
|
if (pts != -1)
|
||||||
close(pts);
|
close(pts);
|
||||||
if (ptmx != -1)
|
if (ptmx != -1)
|
||||||
|
|
@ -245,9 +246,9 @@ slave_spawn(int ptmx, int argc, const char *cwd, char *const *argv,
|
||||||
const char *term_env, const char *conf_shell, bool login_shell,
|
const char *term_env, const char *conf_shell, bool login_shell,
|
||||||
const user_notifications_t *notifications)
|
const user_notifications_t *notifications)
|
||||||
{
|
{
|
||||||
int fork_pipe[2];
|
int error_fd = eventfd(0, EFD_CLOEXEC);
|
||||||
if (pipe2(fork_pipe, O_CLOEXEC) < 0) {
|
if (error_fd < 0) {
|
||||||
LOG_ERRNO("failed to create pipe");
|
LOG_ERRNO("failed to create event FD");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -255,18 +256,16 @@ slave_spawn(int ptmx, int argc, const char *cwd, char *const *argv,
|
||||||
switch (pid) {
|
switch (pid) {
|
||||||
case -1:
|
case -1:
|
||||||
LOG_ERRNO("failed to fork");
|
LOG_ERRNO("failed to fork");
|
||||||
close(fork_pipe[0]);
|
close(error_fd);
|
||||||
close(fork_pipe[1]);
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
case 0:
|
case 0:
|
||||||
/* Child */
|
/* Child */
|
||||||
close(fork_pipe[0]); /* Close read end */
|
|
||||||
|
|
||||||
if (chdir(cwd) < 0) {
|
if (chdir(cwd) < 0) {
|
||||||
const int _errno = errno;
|
const int _errno = errno;
|
||||||
LOG_ERRNO("failed to change working directory");
|
LOG_ERRNO("failed to change working directory");
|
||||||
(void)!write(fork_pipe[1], &_errno, sizeof(_errno));
|
(void)!write(error_fd, &(uint64_t){_errno}, sizeof(uint64_t));
|
||||||
_exit(_errno);
|
_exit(_errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -281,7 +280,7 @@ slave_spawn(int ptmx, int argc, const char *cwd, char *const *argv,
|
||||||
{
|
{
|
||||||
const int _errno = errno;
|
const int _errno = errno;
|
||||||
LOG_ERRNO_P("failed to restore signals", errno);
|
LOG_ERRNO_P("failed to restore signals", errno);
|
||||||
(void)!write(fork_pipe[1], &_errno, sizeof(_errno));
|
(void)!write(error_fd, &(uint64_t){_errno}, sizeof(uint64_t));
|
||||||
_exit(_errno);
|
_exit(_errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -293,9 +292,10 @@ slave_spawn(int ptmx, int argc, const char *cwd, char *const *argv,
|
||||||
if (argc == 0) {
|
if (argc == 0) {
|
||||||
char *shell_copy = strdup(conf_shell);
|
char *shell_copy = strdup(conf_shell);
|
||||||
if (!tokenize_cmdline(shell_copy, &_shell_argv)) {
|
if (!tokenize_cmdline(shell_copy, &_shell_argv)) {
|
||||||
|
const int _errno = errno;
|
||||||
free(shell_copy);
|
free(shell_copy);
|
||||||
(void)!write(fork_pipe[1], &errno, sizeof(errno));
|
(void)!write(error_fd, &(uint64_t){_errno}, sizeof(uint64_t));
|
||||||
_exit(0);
|
_exit(_errno);
|
||||||
}
|
}
|
||||||
shell_argv = _shell_argv;
|
shell_argv = _shell_argv;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -311,26 +311,23 @@ slave_spawn(int ptmx, int argc, const char *cwd, char *const *argv,
|
||||||
if (is_valid_shell(shell_argv[0]))
|
if (is_valid_shell(shell_argv[0]))
|
||||||
setenv("SHELL", shell_argv[0], 1);
|
setenv("SHELL", shell_argv[0], 1);
|
||||||
|
|
||||||
slave_exec(ptmx, shell_argv, fork_pipe[1], login_shell, notifications);
|
slave_exec(ptmx, shell_argv, error_fd, login_shell, notifications);
|
||||||
assert(false);
|
assert(false);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
close(fork_pipe[1]); /* Close write end */
|
|
||||||
LOG_DBG("slave has PID %d", pid);
|
LOG_DBG("slave has PID %d", pid);
|
||||||
|
|
||||||
int _errno;
|
uint64_t _errno;
|
||||||
static_assert(sizeof(errno) == sizeof(_errno), "errno size mismatch");
|
ssize_t ret = read(error_fd, &_errno, sizeof(_errno));
|
||||||
|
close(error_fd);
|
||||||
ssize_t ret = read(fork_pipe[0], &_errno, sizeof(_errno));
|
|
||||||
close(fork_pipe[0]);
|
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
LOG_ERRNO("failed to read from pipe");
|
LOG_ERRNO("failed to read from error FD");
|
||||||
return -1;
|
return -1;
|
||||||
} else if (ret == sizeof(_errno)) {
|
} else if (ret == sizeof(_errno)) {
|
||||||
LOG_ERRNO_P(
|
LOG_ERRNO_P(
|
||||||
"%s: failed to execute", _errno, argc == 0 ? conf_shell : argv[0]);
|
"%s: failed to execute", (int)_errno, argc == 0 ? conf_shell : argv[0]);
|
||||||
return -1;
|
return -1;
|
||||||
} else
|
} else
|
||||||
LOG_DBG("%s: successfully started", conf_shell);
|
LOG_DBG("%s: successfully started", conf_shell);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue