mirror of
https://github.com/DreamMaoMao/maomaowm.git
synced 2026-06-05 03:01:38 -04:00
opt: spawn use double fork
Some checks failed
Generate Nix Options Docs / update-docs (push) Has been cancelled
Some checks failed
Generate Nix Options Docs / update-docs (push) Has been cancelled
This commit is contained in:
parent
1c6b96a38f
commit
21802a3a58
3 changed files with 104 additions and 33 deletions
|
|
@ -1,12 +1,14 @@
|
|||
/* See LICENSE.dwm file for copyright and license details. */
|
||||
#include "util.h"
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "util.h"
|
||||
#include <sys/resource.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define PCRE2_CODE_UNIT_WIDTH 8
|
||||
#include <pcre2.h>
|
||||
|
|
@ -205,4 +207,31 @@ void wl_list_swap(struct wl_list *l1, struct wl_list *l2) {
|
|||
tmp2_prev->next = l1;
|
||||
tmp2_next->prev = l1;
|
||||
}
|
||||
}
|
||||
void restore_nofile_limit(void) {
|
||||
struct rlimit rl;
|
||||
if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
|
||||
// Restore the soft limit to the hard limit
|
||||
rl.rlim_cur = rl.rlim_max;
|
||||
if (setrlimit(RLIMIT_NOFILE, &rl) != 0) {
|
||||
wlr_log(WLR_DEBUG, "restore_nofile_limit: setrlimit failed");
|
||||
}
|
||||
} else {
|
||||
wlr_log(WLR_DEBUG, "restore_nofile_limit: getrlimit failed");
|
||||
}
|
||||
}
|
||||
|
||||
void reset_child_environment(void) {
|
||||
restore_nofile_limit();
|
||||
|
||||
setsid();
|
||||
|
||||
// Reset signal handlers
|
||||
sigset_t set;
|
||||
sigemptyset(&set);
|
||||
sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
|
||||
// Reset signal handlers to default
|
||||
signal(SIGPIPE, SIG_DFL);
|
||||
signal(SIGCHLD, SIG_DFL);
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
/* See LICENSE.dwm file for copyright and license details. */
|
||||
#include <wayland-util.h>
|
||||
#include <time.h>
|
||||
|
||||
void die(const char *fmt, ...);
|
||||
void *ecalloc(size_t nmemb, size_t size);
|
||||
|
|
@ -12,4 +13,5 @@ char *join_strings(char *arr[], const char *sep);
|
|||
char *join_strings_with_suffix(char *arr[], const char *suffix,
|
||||
const char *sep);
|
||||
char *string_printf(const char *fmt, ...);
|
||||
void wl_list_swap(struct wl_list *l1, struct wl_list *l2);
|
||||
void wl_list_swap(struct wl_list *l1, struct wl_list *l2);
|
||||
void reset_child_environment(void);
|
||||
|
|
|
|||
|
|
@ -907,22 +907,40 @@ int32_t spawn_shell(const Arg *arg) {
|
|||
if (!arg->v)
|
||||
return 0;
|
||||
|
||||
if (fork() == 0) {
|
||||
signal(SIGSEGV, SIG_IGN);
|
||||
signal(SIGABRT, SIG_IGN);
|
||||
signal(SIGILL, SIG_IGN);
|
||||
|
||||
dup2(STDERR_FILENO, STDOUT_FILENO);
|
||||
setsid();
|
||||
|
||||
execlp("sh", "sh", "-c", arg->v, (char *)NULL);
|
||||
execlp("bash", "bash", "-c", arg->v, (char *)NULL);
|
||||
|
||||
wlr_log(WLR_DEBUG,
|
||||
"mango: failed to execute command '%s' with shell: %s\n",
|
||||
arg->v, strerror(errno));
|
||||
_exit(EXIT_FAILURE);
|
||||
pid_t child = fork();
|
||||
if (child == -1) {
|
||||
wlr_log_errno(WLR_ERROR, "spawn_shell: first fork failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (child == 0) {
|
||||
// 重置子进程环境与信号
|
||||
reset_child_environment();
|
||||
|
||||
pid_t grandchild = fork();
|
||||
if (grandchild == -1) {
|
||||
wlr_log_errno(WLR_ERROR, "spawn_shell: second fork failed");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (grandchild == 0) {
|
||||
// 孙进程负责实际执行
|
||||
execlp("sh", "sh", "-c", arg->v, (char *)NULL);
|
||||
|
||||
// fallback to bash
|
||||
execlp("bash", "bash", "-c", arg->v, (char *)NULL);
|
||||
|
||||
// 如果两个 shell 都启动失败
|
||||
wlr_log_errno(WLR_ERROR, "spawn_shell: execlp failed for '%s'",
|
||||
(char *)arg->v);
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// 子进程创建完孙进程后立即退出,主进程的 waitpid 瞬间返回
|
||||
_exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
waitpid(child, NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -930,27 +948,49 @@ int32_t spawn(const Arg *arg) {
|
|||
if (!arg->v)
|
||||
return 0;
|
||||
|
||||
if (fork() == 0) {
|
||||
signal(SIGSEGV, SIG_IGN);
|
||||
signal(SIGABRT, SIG_IGN);
|
||||
signal(SIGILL, SIG_IGN);
|
||||
pid_t child = fork();
|
||||
if (child == -1) {
|
||||
wlr_log_errno(WLR_ERROR, "spawn: first fork failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dup2(STDERR_FILENO, STDOUT_FILENO);
|
||||
setsid();
|
||||
if (child == 0) {
|
||||
// 重置子进程环境与信号
|
||||
reset_child_environment();
|
||||
|
||||
wordexp_t p;
|
||||
if (wordexp(arg->v, &p, 0) != 0) {
|
||||
wlr_log(WLR_DEBUG, "mango: wordexp failed for '%s'\n", arg->v);
|
||||
// create second child
|
||||
pid_t grandchild = fork();
|
||||
if (grandchild == -1) {
|
||||
wlr_log_errno(WLR_ERROR, "spawn: second fork failed");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
execvp(p.we_wordv[0], p.we_wordv);
|
||||
if (grandchild == 0) {
|
||||
// execute actual command
|
||||
wordexp_t p;
|
||||
|
||||
wlr_log(WLR_DEBUG, "mango: execvp '%s' failed: %s\n", p.we_wordv[0],
|
||||
strerror(errno));
|
||||
wordfree(&p);
|
||||
_exit(EXIT_FAILURE);
|
||||
if (wordexp(arg->v, &p, 0) != 0) {
|
||||
wlr_log(WLR_ERROR, "mango: wordexp failed for '%s'",
|
||||
(char *)arg->v);
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// 执行成功的话,当前进程映像会被替换,自动释放堆内存
|
||||
execvp(p.we_wordv[0], p.we_wordv);
|
||||
|
||||
// 只有 execvp 失败时才会走到这里
|
||||
wlr_log_errno(WLR_ERROR, "spawn: execvp '%s' failed",
|
||||
p.we_wordv[0]);
|
||||
|
||||
wordfree(&p);
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// 子进程退出,孙进程交由 init (systemd) 托管
|
||||
_exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
waitpid(child, NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue