2017-12-04 22:43:49 +01:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <stdint.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <sys/wait.h>
|
|
|
|
|
#include <unistd.h>
|
2018-08-01 23:21:29 +10:00
|
|
|
#include <signal.h>
|
2017-12-04 22:43:49 +01:00
|
|
|
#include "sway/commands.h"
|
2017-12-05 10:40:55 +01:00
|
|
|
#include "sway/config.h"
|
2021-10-21 21:52:17 +02:00
|
|
|
#include "sway/server.h"
|
2022-11-16 15:50:34 -07:00
|
|
|
#include "sway/desktop/launcher.h"
|
2018-03-29 23:41:33 -04:00
|
|
|
#include "sway/tree/container.h"
|
2018-08-26 12:05:16 +10:00
|
|
|
#include "sway/tree/root.h"
|
2018-03-29 23:41:33 -04:00
|
|
|
#include "sway/tree/workspace.h"
|
2017-12-04 22:43:49 +01:00
|
|
|
#include "log.h"
|
|
|
|
|
#include "stringop.h"
|
|
|
|
|
|
2020-08-23 13:59:22 +02:00
|
|
|
struct cmd_results *cmd_exec_validate(int argc, char **argv) {
|
2017-12-04 22:43:49 +01:00
|
|
|
struct cmd_results *error = NULL;
|
2018-10-23 10:17:58 +01:00
|
|
|
if ((error = checkarg(argc, argv[-1], EXPECTED_AT_LEAST, 1))) {
|
2017-12-04 22:43:49 +01:00
|
|
|
return error;
|
|
|
|
|
}
|
2020-08-23 13:59:22 +02:00
|
|
|
if (!config->active || config->validating) {
|
|
|
|
|
return cmd_results_new(CMD_DEFER, NULL);
|
|
|
|
|
}
|
|
|
|
|
return error;
|
|
|
|
|
}
|
2017-12-04 22:43:49 +01:00
|
|
|
|
2020-08-23 13:59:22 +02:00
|
|
|
struct cmd_results *cmd_exec_process(int argc, char **argv) {
|
|
|
|
|
struct cmd_results *error = NULL;
|
2021-02-02 00:20:15 -05:00
|
|
|
char *cmd = NULL;
|
2022-11-16 15:50:34 -07:00
|
|
|
bool no_startup_id = false;
|
2018-08-28 15:19:52 +01:00
|
|
|
if (strcmp(argv[0], "--no-startup-id") == 0) {
|
2022-11-16 15:50:34 -07:00
|
|
|
no_startup_id = true;
|
2018-08-28 15:19:52 +01:00
|
|
|
--argc; ++argv;
|
2018-10-23 10:17:58 +01:00
|
|
|
if ((error = checkarg(argc, argv[-1], EXPECTED_AT_LEAST, 1))) {
|
2017-12-04 22:43:49 +01:00
|
|
|
return error;
|
|
|
|
|
}
|
2018-08-11 00:52:53 +01:00
|
|
|
}
|
|
|
|
|
|
2018-08-28 15:19:52 +01:00
|
|
|
if (argc == 1 && (argv[0][0] == '\'' || argv[0][0] == '"')) {
|
2021-02-02 00:20:15 -05:00
|
|
|
cmd = strdup(argv[0]);
|
|
|
|
|
strip_quotes(cmd);
|
2017-12-04 22:43:49 +01:00
|
|
|
} else {
|
2021-02-02 00:20:15 -05:00
|
|
|
cmd = join_args(argv, argc);
|
2017-12-04 22:43:49 +01:00
|
|
|
}
|
|
|
|
|
|
2019-01-20 13:51:12 -05:00
|
|
|
sway_log(SWAY_DEBUG, "Executing %s", cmd);
|
2017-12-04 22:43:49 +01:00
|
|
|
|
2022-11-30 11:54:15 -07:00
|
|
|
struct launcher_ctx *ctx = launcher_ctx_create_internal();
|
Rework fork/exec strategy
cmd_exec_process is used whenever sway is meant to execute a child
process on behalf of the user, and had a lot of complexity.
In order to avoid having to wait on the user's process, a double-fork
was used, which in turn required us to wait on the outer process. In
order to track the child PID for launcher purposes, a pipe was used to
transmit the PID back to sway.
This resulted in sway blocking for 5-6 ms per exec on my system, which
is quite significant. The error handling was also quite lacking - the
read loop did not handle errors at all for example.
Instead, teach sway to handle SIGCHLD and do away with the double-fork.
This in turn allows us to get rid of the pipe as we can record the
child's PID directly. This reduces the time we block to just 1.5 ms on
my system. We'd be able to get down to just 150 µs if we could use
posix_spawn(3), but posix_spawn(3) cannot reset NOFILE. clone(2) or
vfork(2) would be alternatives, but that presents portability issues.
This change is replicated for swaybar, swaybg and swaynag handling,
which had similar albeit less complicated implementations.
2025-02-11 12:41:59 +01:00
|
|
|
|
2017-12-04 22:43:49 +01:00
|
|
|
// Fork process
|
Rework fork/exec strategy
cmd_exec_process is used whenever sway is meant to execute a child
process on behalf of the user, and had a lot of complexity.
In order to avoid having to wait on the user's process, a double-fork
was used, which in turn required us to wait on the outer process. In
order to track the child PID for launcher purposes, a pipe was used to
transmit the PID back to sway.
This resulted in sway blocking for 5-6 ms per exec on my system, which
is quite significant. The error handling was also quite lacking - the
read loop did not handle errors at all for example.
Instead, teach sway to handle SIGCHLD and do away with the double-fork.
This in turn allows us to get rid of the pipe as we can record the
child's PID directly. This reduces the time we block to just 1.5 ms on
my system. We'd be able to get down to just 150 µs if we could use
posix_spawn(3), but posix_spawn(3) cannot reset NOFILE. clone(2) or
vfork(2) would be alternatives, but that presents portability issues.
This change is replicated for swaybar, swaybg and swaynag handling,
which had similar albeit less complicated implementations.
2025-02-11 12:41:59 +01:00
|
|
|
pid_t child = fork();
|
|
|
|
|
if (child == 0) {
|
2017-12-04 22:43:49 +01:00
|
|
|
setsid();
|
Rework fork/exec strategy
cmd_exec_process is used whenever sway is meant to execute a child
process on behalf of the user, and had a lot of complexity.
In order to avoid having to wait on the user's process, a double-fork
was used, which in turn required us to wait on the outer process. In
order to track the child PID for launcher purposes, a pipe was used to
transmit the PID back to sway.
This resulted in sway blocking for 5-6 ms per exec on my system, which
is quite significant. The error handling was also quite lacking - the
read loop did not handle errors at all for example.
Instead, teach sway to handle SIGCHLD and do away with the double-fork.
This in turn allows us to get rid of the pipe as we can record the
child's PID directly. This reduces the time we block to just 1.5 ms on
my system. We'd be able to get down to just 150 µs if we could use
posix_spawn(3), but posix_spawn(3) cannot reset NOFILE. clone(2) or
vfork(2) would be alternatives, but that presents portability issues.
This change is replicated for swaybar, swaybg and swaynag handling,
which had similar albeit less complicated implementations.
2025-02-11 12:41:59 +01:00
|
|
|
|
|
|
|
|
if (ctx) {
|
|
|
|
|
const char *token = launcher_ctx_get_token_name(ctx);
|
|
|
|
|
setenv("XDG_ACTIVATION_TOKEN", token, 1);
|
|
|
|
|
if (!no_startup_id) {
|
|
|
|
|
setenv("DESKTOP_STARTUP_ID", token, 1);
|
2022-11-18 20:05:24 -07:00
|
|
|
}
|
2018-07-01 00:00:15 +09:00
|
|
|
}
|
Rework fork/exec strategy
cmd_exec_process is used whenever sway is meant to execute a child
process on behalf of the user, and had a lot of complexity.
In order to avoid having to wait on the user's process, a double-fork
was used, which in turn required us to wait on the outer process. In
order to track the child PID for launcher purposes, a pipe was used to
transmit the PID back to sway.
This resulted in sway blocking for 5-6 ms per exec on my system, which
is quite significant. The error handling was also quite lacking - the
read loop did not handle errors at all for example.
Instead, teach sway to handle SIGCHLD and do away with the double-fork.
This in turn allows us to get rid of the pipe as we can record the
child's PID directly. This reduces the time we block to just 1.5 ms on
my system. We'd be able to get down to just 150 µs if we could use
posix_spawn(3), but posix_spawn(3) cannot reset NOFILE. clone(2) or
vfork(2) would be alternatives, but that presents portability issues.
This change is replicated for swaybar, swaybg and swaynag handling,
which had similar albeit less complicated implementations.
2025-02-11 12:41:59 +01:00
|
|
|
|
|
|
|
|
execlp("sh", "sh", "-c", cmd, (void*)NULL);
|
|
|
|
|
sway_log_errno(SWAY_ERROR, "execve failed");
|
2017-12-04 22:43:49 +01:00
|
|
|
_exit(0); // Close child process
|
Rework fork/exec strategy
cmd_exec_process is used whenever sway is meant to execute a child
process on behalf of the user, and had a lot of complexity.
In order to avoid having to wait on the user's process, a double-fork
was used, which in turn required us to wait on the outer process. In
order to track the child PID for launcher purposes, a pipe was used to
transmit the PID back to sway.
This resulted in sway blocking for 5-6 ms per exec on my system, which
is quite significant. The error handling was also quite lacking - the
read loop did not handle errors at all for example.
Instead, teach sway to handle SIGCHLD and do away with the double-fork.
This in turn allows us to get rid of the pipe as we can record the
child's PID directly. This reduces the time we block to just 1.5 ms on
my system. We'd be able to get down to just 150 µs if we could use
posix_spawn(3), but posix_spawn(3) cannot reset NOFILE. clone(2) or
vfork(2) would be alternatives, but that presents portability issues.
This change is replicated for swaybar, swaybg and swaynag handling,
which had similar albeit less complicated implementations.
2025-02-11 12:41:59 +01:00
|
|
|
} else if (child < 0) {
|
|
|
|
|
launcher_ctx_destroy(ctx);
|
2021-02-02 00:20:15 -05:00
|
|
|
free(cmd);
|
2019-01-10 18:27:21 -05:00
|
|
|
return cmd_results_new(CMD_FAILURE, "fork() failed");
|
2017-12-04 22:43:49 +01:00
|
|
|
}
|
Rework fork/exec strategy
cmd_exec_process is used whenever sway is meant to execute a child
process on behalf of the user, and had a lot of complexity.
In order to avoid having to wait on the user's process, a double-fork
was used, which in turn required us to wait on the outer process. In
order to track the child PID for launcher purposes, a pipe was used to
transmit the PID back to sway.
This resulted in sway blocking for 5-6 ms per exec on my system, which
is quite significant. The error handling was also quite lacking - the
read loop did not handle errors at all for example.
Instead, teach sway to handle SIGCHLD and do away with the double-fork.
This in turn allows us to get rid of the pipe as we can record the
child's PID directly. This reduces the time we block to just 1.5 ms on
my system. We'd be able to get down to just 150 µs if we could use
posix_spawn(3), but posix_spawn(3) cannot reset NOFILE. clone(2) or
vfork(2) would be alternatives, but that presents portability issues.
This change is replicated for swaybar, swaybg and swaynag handling,
which had similar albeit less complicated implementations.
2025-02-11 12:41:59 +01:00
|
|
|
|
|
|
|
|
sway_log(SWAY_DEBUG, "Child process created with pid %d", child);
|
|
|
|
|
if (ctx != NULL) {
|
|
|
|
|
sway_log(SWAY_DEBUG, "Recording workspace for process %d", child);
|
|
|
|
|
ctx->pid = child;
|
2017-12-04 22:43:49 +01:00
|
|
|
}
|
|
|
|
|
|
Rework fork/exec strategy
cmd_exec_process is used whenever sway is meant to execute a child
process on behalf of the user, and had a lot of complexity.
In order to avoid having to wait on the user's process, a double-fork
was used, which in turn required us to wait on the outer process. In
order to track the child PID for launcher purposes, a pipe was used to
transmit the PID back to sway.
This resulted in sway blocking for 5-6 ms per exec on my system, which
is quite significant. The error handling was also quite lacking - the
read loop did not handle errors at all for example.
Instead, teach sway to handle SIGCHLD and do away with the double-fork.
This in turn allows us to get rid of the pipe as we can record the
child's PID directly. This reduces the time we block to just 1.5 ms on
my system. We'd be able to get down to just 150 µs if we could use
posix_spawn(3), but posix_spawn(3) cannot reset NOFILE. clone(2) or
vfork(2) would be alternatives, but that presents portability issues.
This change is replicated for swaybar, swaybg and swaynag handling,
which had similar albeit less complicated implementations.
2025-02-11 12:41:59 +01:00
|
|
|
free(cmd);
|
2019-01-10 18:27:21 -05:00
|
|
|
return cmd_results_new(CMD_SUCCESS, NULL);
|
2017-12-04 22:43:49 +01:00
|
|
|
}
|
2020-08-23 13:59:22 +02:00
|
|
|
|
|
|
|
|
struct cmd_results *cmd_exec_always(int argc, char **argv) {
|
|
|
|
|
struct cmd_results *error;
|
|
|
|
|
if ((error = cmd_exec_validate(argc, argv))) {
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
return cmd_exec_process(argc, argv);
|
|
|
|
|
}
|