##// END OF EJS Templates
rust-chg: remove SIGCHLD handler which won't work in oxidized chg...
Yuya Nishihara -
r40155:e70b616a default
parent child Browse files
Show More
@@ -1,177 +1,151
1 /*
1 /*
2 * Signal handlers for cHg
2 * Signal handlers for cHg
3 *
3 *
4 * Copyright 2011, 2018 Yuya Nishihara <yuya@tcha.org>
4 * Copyright 2011, 2018 Yuya Nishihara <yuya@tcha.org>
5 *
5 *
6 * This software may be used and distributed according to the terms of the
6 * This software may be used and distributed according to the terms of the
7 * GNU General Public License version 2 or any later version.
7 * GNU General Public License version 2 or any later version.
8 */
8 */
9
9
10 #include <assert.h>
10 #include <assert.h>
11 #include <errno.h>
11 #include <errno.h>
12 #include <signal.h>
12 #include <signal.h>
13 #include <string.h>
13 #include <string.h>
14 #include <sys/wait.h>
15 #include <unistd.h>
14 #include <unistd.h>
16
15
17 #ifdef __GNUC__
18 #define UNUSED_ __attribute__((unused))
19 #else
20 #define UNUSED_
21 #endif
22
23 static pid_t pagerpid = 0;
24 static pid_t peerpgid = 0;
16 static pid_t peerpgid = 0;
25 static pid_t peerpid = 0;
17 static pid_t peerpid = 0;
26
18
27 static void forwardsignal(int sig)
19 static void forwardsignal(int sig)
28 {
20 {
29 assert(peerpid > 0);
21 assert(peerpid > 0);
30 (void)kill(peerpid, sig);
22 (void)kill(peerpid, sig);
31 }
23 }
32
24
33 static void forwardsignaltogroup(int sig)
25 static void forwardsignaltogroup(int sig)
34 {
26 {
35 /* prefer kill(-pgid, sig), fallback to pid if pgid is invalid */
27 /* prefer kill(-pgid, sig), fallback to pid if pgid is invalid */
36 pid_t killpid = peerpgid > 1 ? -peerpgid : peerpid;
28 pid_t killpid = peerpgid > 1 ? -peerpgid : peerpid;
37 (void)kill(killpid, sig);
29 (void)kill(killpid, sig);
38 }
30 }
39
31
40 static void handlestopsignal(int sig)
32 static void handlestopsignal(int sig)
41 {
33 {
42 sigset_t unblockset, oldset;
34 sigset_t unblockset, oldset;
43 struct sigaction sa, oldsa;
35 struct sigaction sa, oldsa;
44 if (sigemptyset(&unblockset) < 0)
36 if (sigemptyset(&unblockset) < 0)
45 return;
37 return;
46 if (sigaddset(&unblockset, sig) < 0)
38 if (sigaddset(&unblockset, sig) < 0)
47 return;
39 return;
48 memset(&sa, 0, sizeof(sa));
40 memset(&sa, 0, sizeof(sa));
49 sa.sa_handler = SIG_DFL;
41 sa.sa_handler = SIG_DFL;
50 sa.sa_flags = SA_RESTART;
42 sa.sa_flags = SA_RESTART;
51 if (sigemptyset(&sa.sa_mask) < 0)
43 if (sigemptyset(&sa.sa_mask) < 0)
52 return;
44 return;
53
45
54 forwardsignal(sig);
46 forwardsignal(sig);
55 if (raise(sig) < 0) /* resend to self */
47 if (raise(sig) < 0) /* resend to self */
56 return;
48 return;
57 if (sigaction(sig, &sa, &oldsa) < 0)
49 if (sigaction(sig, &sa, &oldsa) < 0)
58 return;
50 return;
59 if (sigprocmask(SIG_UNBLOCK, &unblockset, &oldset) < 0)
51 if (sigprocmask(SIG_UNBLOCK, &unblockset, &oldset) < 0)
60 return;
52 return;
61 /* resent signal will be handled before sigprocmask() returns */
53 /* resent signal will be handled before sigprocmask() returns */
62 if (sigprocmask(SIG_SETMASK, &oldset, NULL) < 0)
54 if (sigprocmask(SIG_SETMASK, &oldset, NULL) < 0)
63 return;
55 return;
64 if (sigaction(sig, &oldsa, NULL) < 0)
56 if (sigaction(sig, &oldsa, NULL) < 0)
65 return;
57 return;
66 }
58 }
67
59
68 static void handlechildsignal(int sig UNUSED_)
69 {
70 if (peerpid == 0 || pagerpid == 0)
71 return;
72 /* if pager exits, notify the server with SIGPIPE immediately.
73 * otherwise the server won't get SIGPIPE if it does not write
74 * anything. (issue5278) */
75 if (waitpid(pagerpid, NULL, WNOHANG) == pagerpid)
76 kill(peerpid, SIGPIPE);
77 }
78
79 /*
60 /*
80 * Installs signal handlers.
61 * Installs signal handlers.
81 *
62 *
82 * Returns 0 on success, -1 on error and errno is set appropriately.
63 * Returns 0 on success, -1 on error and errno is set appropriately.
83 * Installed handlers wouldn't be cleaned up on error.
64 * Installed handlers wouldn't be cleaned up on error.
84 */
65 */
85 int setupsignalhandler(pid_t pid, pid_t pgid)
66 int setupsignalhandler(pid_t pid, pid_t pgid)
86 {
67 {
87 if (pid <= 0) {
68 if (pid <= 0) {
88 errno = EINVAL;
69 errno = EINVAL;
89 return -1;
70 return -1;
90 }
71 }
91 peerpid = pid;
72 peerpid = pid;
92 peerpgid = (pgid <= 1 ? 0 : pgid);
73 peerpgid = (pgid <= 1 ? 0 : pgid);
93
74
94 struct sigaction sa;
75 struct sigaction sa;
95 memset(&sa, 0, sizeof(sa));
76 memset(&sa, 0, sizeof(sa));
96
77
97 /* deadly signals meant to be sent to a process group:
78 /* deadly signals meant to be sent to a process group:
98 * - SIGHUP: usually generated by the kernel, when termination of a
79 * - SIGHUP: usually generated by the kernel, when termination of a
99 * process causes that process group to become orphaned
80 * process causes that process group to become orphaned
100 * - SIGINT: usually generated by the terminal */
81 * - SIGINT: usually generated by the terminal */
101 sa.sa_handler = forwardsignaltogroup;
82 sa.sa_handler = forwardsignaltogroup;
102 sa.sa_flags = SA_RESTART;
83 sa.sa_flags = SA_RESTART;
103 if (sigemptyset(&sa.sa_mask) < 0)
84 if (sigemptyset(&sa.sa_mask) < 0)
104 return -1;
85 return -1;
105 if (sigaction(SIGHUP, &sa, NULL) < 0)
86 if (sigaction(SIGHUP, &sa, NULL) < 0)
106 return -1;
87 return -1;
107 if (sigaction(SIGINT, &sa, NULL) < 0)
88 if (sigaction(SIGINT, &sa, NULL) < 0)
108 return -1;
89 return -1;
109
90
110 /* terminate frontend by double SIGTERM in case of server freeze */
91 /* terminate frontend by double SIGTERM in case of server freeze */
111 sa.sa_handler = forwardsignal;
92 sa.sa_handler = forwardsignal;
112 sa.sa_flags |= SA_RESETHAND;
93 sa.sa_flags |= SA_RESETHAND;
113 if (sigaction(SIGTERM, &sa, NULL) < 0)
94 if (sigaction(SIGTERM, &sa, NULL) < 0)
114 return -1;
95 return -1;
115
96
116 /* notify the worker about window resize events */
97 /* notify the worker about window resize events */
117 sa.sa_flags = SA_RESTART;
98 sa.sa_flags = SA_RESTART;
118 if (sigaction(SIGWINCH, &sa, NULL) < 0)
99 if (sigaction(SIGWINCH, &sa, NULL) < 0)
119 return -1;
100 return -1;
120 /* forward user-defined signals */
101 /* forward user-defined signals */
121 if (sigaction(SIGUSR1, &sa, NULL) < 0)
102 if (sigaction(SIGUSR1, &sa, NULL) < 0)
122 return -1;
103 return -1;
123 if (sigaction(SIGUSR2, &sa, NULL) < 0)
104 if (sigaction(SIGUSR2, &sa, NULL) < 0)
124 return -1;
105 return -1;
125 /* propagate job control requests to worker */
106 /* propagate job control requests to worker */
126 sa.sa_handler = forwardsignal;
107 sa.sa_handler = forwardsignal;
127 sa.sa_flags = SA_RESTART;
108 sa.sa_flags = SA_RESTART;
128 if (sigaction(SIGCONT, &sa, NULL) < 0)
109 if (sigaction(SIGCONT, &sa, NULL) < 0)
129 return -1;
110 return -1;
130 sa.sa_handler = handlestopsignal;
111 sa.sa_handler = handlestopsignal;
131 sa.sa_flags = SA_RESTART;
112 sa.sa_flags = SA_RESTART;
132 if (sigaction(SIGTSTP, &sa, NULL) < 0)
113 if (sigaction(SIGTSTP, &sa, NULL) < 0)
133 return -1;
114 return -1;
134 /* get notified when pager exits */
135 sa.sa_handler = handlechildsignal;
136 sa.sa_flags = SA_RESTART;
137 if (sigaction(SIGCHLD, &sa, NULL) < 0)
138 return -1;
139
115
140 return 0;
116 return 0;
141 }
117 }
142
118
143 /*
119 /*
144 * Restores signal handlers to the default, and masks SIGINT.
120 * Restores signal handlers to the default, and masks SIGINT.
145 *
121 *
146 * Returns 0 on success, -1 on error and errno is set appropriately.
122 * Returns 0 on success, -1 on error and errno is set appropriately.
147 */
123 */
148 int restoresignalhandler(void)
124 int restoresignalhandler(void)
149 {
125 {
150 struct sigaction sa;
126 struct sigaction sa;
151 memset(&sa, 0, sizeof(sa));
127 memset(&sa, 0, sizeof(sa));
152 sa.sa_handler = SIG_DFL;
128 sa.sa_handler = SIG_DFL;
153 sa.sa_flags = SA_RESTART;
129 sa.sa_flags = SA_RESTART;
154 if (sigemptyset(&sa.sa_mask) < 0)
130 if (sigemptyset(&sa.sa_mask) < 0)
155 return -1;
131 return -1;
156
132
157 if (sigaction(SIGHUP, &sa, NULL) < 0)
133 if (sigaction(SIGHUP, &sa, NULL) < 0)
158 return -1;
134 return -1;
159 if (sigaction(SIGTERM, &sa, NULL) < 0)
135 if (sigaction(SIGTERM, &sa, NULL) < 0)
160 return -1;
136 return -1;
161 if (sigaction(SIGWINCH, &sa, NULL) < 0)
137 if (sigaction(SIGWINCH, &sa, NULL) < 0)
162 return -1;
138 return -1;
163 if (sigaction(SIGCONT, &sa, NULL) < 0)
139 if (sigaction(SIGCONT, &sa, NULL) < 0)
164 return -1;
140 return -1;
165 if (sigaction(SIGTSTP, &sa, NULL) < 0)
141 if (sigaction(SIGTSTP, &sa, NULL) < 0)
166 return -1;
142 return -1;
167 if (sigaction(SIGCHLD, &sa, NULL) < 0)
168 return -1;
169
143
170 /* ignore Ctrl+C while shutting down to make pager exits cleanly */
144 /* ignore Ctrl+C while shutting down to make pager exits cleanly */
171 sa.sa_handler = SIG_IGN;
145 sa.sa_handler = SIG_IGN;
172 if (sigaction(SIGINT, &sa, NULL) < 0)
146 if (sigaction(SIGINT, &sa, NULL) < 0)
173 return -1;
147 return -1;
174
148
175 peerpid = 0;
149 peerpid = 0;
176 return 0;
150 return 0;
177 }
151 }
@@ -1,83 +1,87
1 // Copyright 2018 Yuya Nishihara <yuya@tcha.org>
1 // Copyright 2018 Yuya Nishihara <yuya@tcha.org>
2 //
2 //
3 // This software may be used and distributed according to the terms of the
3 // This software may be used and distributed according to the terms of the
4 // GNU General Public License version 2 or any later version.
4 // GNU General Public License version 2 or any later version.
5
5
6 use futures::Future;
6 use futures::Future;
7 use futures::future::IntoFuture;
7 use futures::future::IntoFuture;
8 use std::io;
8 use std::io;
9 use std::os::unix::io::AsRawFd;
9 use std::os::unix::io::AsRawFd;
10 use std::os::unix::process::ExitStatusExt;
10 use std::os::unix::process::ExitStatusExt;
11 use std::process::{Command, Stdio};
11 use std::process::{Command, Stdio};
12 use tokio;
12 use tokio;
13 use tokio_process::{ChildStdin, CommandExt};
13 use tokio_process::{ChildStdin, CommandExt};
14
14
15 use super::message::CommandSpec;
15 use super::message::CommandSpec;
16 use super::procutil;
16 use super::procutil;
17
17
18 /// Callback to process shell command requests received from server.
18 /// Callback to process shell command requests received from server.
19 pub trait SystemHandler: Sized {
19 pub trait SystemHandler: Sized {
20 type PagerStdin: AsRawFd;
20 type PagerStdin: AsRawFd;
21 type SpawnPagerResult: IntoFuture<Item = (Self, Self::PagerStdin), Error = io::Error>;
21 type SpawnPagerResult: IntoFuture<Item = (Self, Self::PagerStdin), Error = io::Error>;
22 type RunSystemResult: IntoFuture<Item = (Self, i32), Error = io::Error>;
22 type RunSystemResult: IntoFuture<Item = (Self, i32), Error = io::Error>;
23
23
24 /// Handles pager command request.
24 /// Handles pager command request.
25 ///
25 ///
26 /// Returns the pipe to be attached to the server if the pager is spawned.
26 /// Returns the pipe to be attached to the server if the pager is spawned.
27 fn spawn_pager(self, spec: CommandSpec) -> Self::SpawnPagerResult;
27 fn spawn_pager(self, spec: CommandSpec) -> Self::SpawnPagerResult;
28
28
29 /// Handles system command request.
29 /// Handles system command request.
30 ///
30 ///
31 /// Returns command exit code (positive) or signal number (negative).
31 /// Returns command exit code (positive) or signal number (negative).
32 fn run_system(self, spec: CommandSpec) -> Self::RunSystemResult;
32 fn run_system(self, spec: CommandSpec) -> Self::RunSystemResult;
33 }
33 }
34
34
35 /// Default cHg implementation to process requests received from server.
35 /// Default cHg implementation to process requests received from server.
36 pub struct ChgUiHandler {
36 pub struct ChgUiHandler {
37 }
37 }
38
38
39 impl ChgUiHandler {
39 impl ChgUiHandler {
40 pub fn new() -> ChgUiHandler {
40 pub fn new() -> ChgUiHandler {
41 ChgUiHandler {}
41 ChgUiHandler {}
42 }
42 }
43 }
43 }
44
44
45 impl SystemHandler for ChgUiHandler {
45 impl SystemHandler for ChgUiHandler {
46 type PagerStdin = ChildStdin;
46 type PagerStdin = ChildStdin;
47 type SpawnPagerResult = io::Result<(Self, Self::PagerStdin)>;
47 type SpawnPagerResult = io::Result<(Self, Self::PagerStdin)>;
48 type RunSystemResult = Box<dyn Future<Item = (Self, i32), Error = io::Error> + Send>;
48 type RunSystemResult = Box<dyn Future<Item = (Self, i32), Error = io::Error> + Send>;
49
49
50 fn spawn_pager(self, spec: CommandSpec) -> Self::SpawnPagerResult {
50 fn spawn_pager(self, spec: CommandSpec) -> Self::SpawnPagerResult {
51 let mut pager = new_shell_command(&spec)
51 let mut pager = new_shell_command(&spec)
52 .stdin(Stdio::piped())
52 .stdin(Stdio::piped())
53 .spawn_async()?;
53 .spawn_async()?;
54 let pin = pager.stdin().take().unwrap();
54 let pin = pager.stdin().take().unwrap();
55 procutil::set_blocking_fd(pin.as_raw_fd())?;
55 procutil::set_blocking_fd(pin.as_raw_fd())?;
56 // TODO: if pager exits, notify the server with SIGPIPE immediately.
57 // otherwise the server won't get SIGPIPE if it does not write
58 // anything. (issue5278)
59 // kill(peerpid, SIGPIPE);
56 tokio::spawn(pager.map(|_| ()).map_err(|_| ())); // just ignore errors
60 tokio::spawn(pager.map(|_| ()).map_err(|_| ())); // just ignore errors
57 Ok((self, pin))
61 Ok((self, pin))
58 }
62 }
59
63
60 fn run_system(self, spec: CommandSpec) -> Self::RunSystemResult {
64 fn run_system(self, spec: CommandSpec) -> Self::RunSystemResult {
61 let fut = new_shell_command(&spec)
65 let fut = new_shell_command(&spec)
62 .spawn_async()
66 .spawn_async()
63 .into_future()
67 .into_future()
64 .flatten()
68 .flatten()
65 .map(|status| {
69 .map(|status| {
66 let code = status.code().or_else(|| status.signal().map(|n| -n))
70 let code = status.code().or_else(|| status.signal().map(|n| -n))
67 .expect("either exit code or signal should be set");
71 .expect("either exit code or signal should be set");
68 (self, code)
72 (self, code)
69 });
73 });
70 Box::new(fut)
74 Box::new(fut)
71 }
75 }
72 }
76 }
73
77
74 fn new_shell_command(spec: &CommandSpec) -> Command {
78 fn new_shell_command(spec: &CommandSpec) -> Command {
75 let mut builder = Command::new("/bin/sh");
79 let mut builder = Command::new("/bin/sh");
76 builder
80 builder
77 .arg("-c")
81 .arg("-c")
78 .arg(&spec.command)
82 .arg(&spec.command)
79 .current_dir(&spec.current_dir)
83 .current_dir(&spec.current_dir)
80 .env_clear()
84 .env_clear()
81 .envs(spec.envs.iter().cloned());
85 .envs(spec.envs.iter().cloned());
82 builder
86 builder
83 }
87 }
General Comments 0
You need to be logged in to leave comments. Login now