##// END OF EJS Templates
rust-chg: extract signal handlers from chg/procutil.c...
Yuya Nishihara -
r40154:cd490ac9 default
parent child Browse files
Show More
@@ -4,5 +4,6 b' fn main() {'
4 cc::Build::new()
4 cc::Build::new()
5 .warnings(true)
5 .warnings(true)
6 .file("src/sendfds.c")
6 .file("src/sendfds.c")
7 .file("src/sighandlers.c")
7 .compile("procutil");
8 .compile("procutil");
8 }
9 }
@@ -1,7 +1,7 b''
1 /*
1 /*
2 * Utilities about process handling - signal and subprocess (ex. pager)
2 * Signal handlers for cHg
3 *
3 *
4 * Copyright (c) 2011 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.
@@ -10,13 +10,15 b''
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 <stdio.h>
14 #include <string.h>
13 #include <string.h>
15 #include <sys/wait.h>
14 #include <sys/wait.h>
16 #include <unistd.h>
15 #include <unistd.h>
17
16
18 #include "procutil.h"
17 #ifdef __GNUC__
19 #include "util.h"
18 #define UNUSED_ __attribute__((unused))
19 #else
20 #define UNUSED_
21 #endif
20
22
21 static pid_t pagerpid = 0;
23 static pid_t pagerpid = 0;
22 static pid_t peerpgid = 0;
24 static pid_t peerpgid = 0;
@@ -25,18 +27,14 b' static pid_t peerpid = 0;'
25 static void forwardsignal(int sig)
27 static void forwardsignal(int sig)
26 {
28 {
27 assert(peerpid > 0);
29 assert(peerpid > 0);
28 if (kill(peerpid, sig) < 0)
30 (void)kill(peerpid, sig);
29 abortmsgerrno("cannot kill %d", peerpid);
30 debugmsg("forward signal %d", sig);
31 }
31 }
32
32
33 static void forwardsignaltogroup(int sig)
33 static void forwardsignaltogroup(int sig)
34 {
34 {
35 /* prefer kill(-pgid, sig), fallback to pid if pgid is invalid */
35 /* prefer kill(-pgid, sig), fallback to pid if pgid is invalid */
36 pid_t killpid = peerpgid > 1 ? -peerpgid : peerpid;
36 pid_t killpid = peerpgid > 1 ? -peerpgid : peerpid;
37 if (kill(killpid, sig) < 0)
37 (void)kill(killpid, sig);
38 abortmsgerrno("cannot kill %d", killpid);
39 debugmsg("forward signal %d to %d", sig, killpid);
40 }
38 }
41
39
42 static void handlestopsignal(int sig)
40 static void handlestopsignal(int sig)
@@ -44,31 +42,27 b' static void handlestopsignal(int sig)'
44 sigset_t unblockset, oldset;
42 sigset_t unblockset, oldset;
45 struct sigaction sa, oldsa;
43 struct sigaction sa, oldsa;
46 if (sigemptyset(&unblockset) < 0)
44 if (sigemptyset(&unblockset) < 0)
47 goto error;
45 return;
48 if (sigaddset(&unblockset, sig) < 0)
46 if (sigaddset(&unblockset, sig) < 0)
49 goto error;
47 return;
50 memset(&sa, 0, sizeof(sa));
48 memset(&sa, 0, sizeof(sa));
51 sa.sa_handler = SIG_DFL;
49 sa.sa_handler = SIG_DFL;
52 sa.sa_flags = SA_RESTART;
50 sa.sa_flags = SA_RESTART;
53 if (sigemptyset(&sa.sa_mask) < 0)
51 if (sigemptyset(&sa.sa_mask) < 0)
54 goto error;
52 return;
55
53
56 forwardsignal(sig);
54 forwardsignal(sig);
57 if (raise(sig) < 0) /* resend to self */
55 if (raise(sig) < 0) /* resend to self */
58 goto error;
56 return;
59 if (sigaction(sig, &sa, &oldsa) < 0)
57 if (sigaction(sig, &sa, &oldsa) < 0)
60 goto error;
58 return;
61 if (sigprocmask(SIG_UNBLOCK, &unblockset, &oldset) < 0)
59 if (sigprocmask(SIG_UNBLOCK, &unblockset, &oldset) < 0)
62 goto error;
60 return;
63 /* resent signal will be handled before sigprocmask() returns */
61 /* resent signal will be handled before sigprocmask() returns */
64 if (sigprocmask(SIG_SETMASK, &oldset, NULL) < 0)
62 if (sigprocmask(SIG_SETMASK, &oldset, NULL) < 0)
65 goto error;
66 if (sigaction(sig, &oldsa, NULL) < 0)
67 goto error;
68 return;
63 return;
69
64 if (sigaction(sig, &oldsa, NULL) < 0)
70 error:
65 return;
71 abortmsgerrno("failed to handle stop signal");
72 }
66 }
73
67
74 static void handlechildsignal(int sig UNUSED_)
68 static void handlechildsignal(int sig UNUSED_)
@@ -82,10 +76,18 b' static void handlechildsignal(int sig UN'
82 kill(peerpid, SIGPIPE);
76 kill(peerpid, SIGPIPE);
83 }
77 }
84
78
85 void setupsignalhandler(pid_t pid, pid_t pgid)
79 /*
80 * Installs signal handlers.
81 *
82 * Returns 0 on success, -1 on error and errno is set appropriately.
83 * Installed handlers wouldn't be cleaned up on error.
84 */
85 int setupsignalhandler(pid_t pid, pid_t pgid)
86 {
86 {
87 if (pid <= 0)
87 if (pid <= 0) {
88 return;
88 errno = EINVAL;
89 return -1;
90 }
89 peerpid = pid;
91 peerpid = pid;
90 peerpgid = (pgid <= 1 ? 0 : pgid);
92 peerpgid = (pgid <= 1 ? 0 : pgid);
91
93
@@ -99,139 +101,77 b' void setupsignalhandler(pid_t pid, pid_t'
99 sa.sa_handler = forwardsignaltogroup;
101 sa.sa_handler = forwardsignaltogroup;
100 sa.sa_flags = SA_RESTART;
102 sa.sa_flags = SA_RESTART;
101 if (sigemptyset(&sa.sa_mask) < 0)
103 if (sigemptyset(&sa.sa_mask) < 0)
102 goto error;
104 return -1;
103 if (sigaction(SIGHUP, &sa, NULL) < 0)
105 if (sigaction(SIGHUP, &sa, NULL) < 0)
104 goto error;
106 return -1;
105 if (sigaction(SIGINT, &sa, NULL) < 0)
107 if (sigaction(SIGINT, &sa, NULL) < 0)
106 goto error;
108 return -1;
107
109
108 /* terminate frontend by double SIGTERM in case of server freeze */
110 /* terminate frontend by double SIGTERM in case of server freeze */
109 sa.sa_handler = forwardsignal;
111 sa.sa_handler = forwardsignal;
110 sa.sa_flags |= SA_RESETHAND;
112 sa.sa_flags |= SA_RESETHAND;
111 if (sigaction(SIGTERM, &sa, NULL) < 0)
113 if (sigaction(SIGTERM, &sa, NULL) < 0)
112 goto error;
114 return -1;
113
115
114 /* notify the worker about window resize events */
116 /* notify the worker about window resize events */
115 sa.sa_flags = SA_RESTART;
117 sa.sa_flags = SA_RESTART;
116 if (sigaction(SIGWINCH, &sa, NULL) < 0)
118 if (sigaction(SIGWINCH, &sa, NULL) < 0)
117 goto error;
119 return -1;
118 /* forward user-defined signals */
120 /* forward user-defined signals */
119 if (sigaction(SIGUSR1, &sa, NULL) < 0)
121 if (sigaction(SIGUSR1, &sa, NULL) < 0)
120 goto error;
122 return -1;
121 if (sigaction(SIGUSR2, &sa, NULL) < 0)
123 if (sigaction(SIGUSR2, &sa, NULL) < 0)
122 goto error;
124 return -1;
123 /* propagate job control requests to worker */
125 /* propagate job control requests to worker */
124 sa.sa_handler = forwardsignal;
126 sa.sa_handler = forwardsignal;
125 sa.sa_flags = SA_RESTART;
127 sa.sa_flags = SA_RESTART;
126 if (sigaction(SIGCONT, &sa, NULL) < 0)
128 if (sigaction(SIGCONT, &sa, NULL) < 0)
127 goto error;
129 return -1;
128 sa.sa_handler = handlestopsignal;
130 sa.sa_handler = handlestopsignal;
129 sa.sa_flags = SA_RESTART;
131 sa.sa_flags = SA_RESTART;
130 if (sigaction(SIGTSTP, &sa, NULL) < 0)
132 if (sigaction(SIGTSTP, &sa, NULL) < 0)
131 goto error;
133 return -1;
132 /* get notified when pager exits */
134 /* get notified when pager exits */
133 sa.sa_handler = handlechildsignal;
135 sa.sa_handler = handlechildsignal;
134 sa.sa_flags = SA_RESTART;
136 sa.sa_flags = SA_RESTART;
135 if (sigaction(SIGCHLD, &sa, NULL) < 0)
137 if (sigaction(SIGCHLD, &sa, NULL) < 0)
136 goto error;
138 return -1;
137
139
138 return;
140 return 0;
139
140 error:
141 abortmsgerrno("failed to set up signal handlers");
142 }
141 }
143
142
144 void restoresignalhandler(void)
143 /*
144 * Restores signal handlers to the default, and masks SIGINT.
145 *
146 * Returns 0 on success, -1 on error and errno is set appropriately.
147 */
148 int restoresignalhandler(void)
145 {
149 {
146 struct sigaction sa;
150 struct sigaction sa;
147 memset(&sa, 0, sizeof(sa));
151 memset(&sa, 0, sizeof(sa));
148 sa.sa_handler = SIG_DFL;
152 sa.sa_handler = SIG_DFL;
149 sa.sa_flags = SA_RESTART;
153 sa.sa_flags = SA_RESTART;
150 if (sigemptyset(&sa.sa_mask) < 0)
154 if (sigemptyset(&sa.sa_mask) < 0)
151 goto error;
155 return -1;
152
156
153 if (sigaction(SIGHUP, &sa, NULL) < 0)
157 if (sigaction(SIGHUP, &sa, NULL) < 0)
154 goto error;
158 return -1;
155 if (sigaction(SIGTERM, &sa, NULL) < 0)
159 if (sigaction(SIGTERM, &sa, NULL) < 0)
156 goto error;
160 return -1;
157 if (sigaction(SIGWINCH, &sa, NULL) < 0)
161 if (sigaction(SIGWINCH, &sa, NULL) < 0)
158 goto error;
162 return -1;
159 if (sigaction(SIGCONT, &sa, NULL) < 0)
163 if (sigaction(SIGCONT, &sa, NULL) < 0)
160 goto error;
164 return -1;
161 if (sigaction(SIGTSTP, &sa, NULL) < 0)
165 if (sigaction(SIGTSTP, &sa, NULL) < 0)
162 goto error;
166 return -1;
163 if (sigaction(SIGCHLD, &sa, NULL) < 0)
167 if (sigaction(SIGCHLD, &sa, NULL) < 0)
164 goto error;
168 return -1;
165
169
166 /* ignore Ctrl+C while shutting down to make pager exits cleanly */
170 /* ignore Ctrl+C while shutting down to make pager exits cleanly */
167 sa.sa_handler = SIG_IGN;
171 sa.sa_handler = SIG_IGN;
168 if (sigaction(SIGINT, &sa, NULL) < 0)
172 if (sigaction(SIGINT, &sa, NULL) < 0)
169 goto error;
173 return -1;
170
174
171 peerpid = 0;
175 peerpid = 0;
172 return;
173
174 error:
175 abortmsgerrno("failed to restore signal handlers");
176 }
177
178 /* This implementation is based on hgext/pager.py (post 369741ef7253)
179 * Return 0 if pager is not started, or pid of the pager */
180 pid_t setuppager(const char *pagercmd, const char *envp[])
181 {
182 assert(pagerpid == 0);
183 if (!pagercmd)
184 return 0;
185
186 int pipefds[2];
187 if (pipe(pipefds) < 0)
188 return 0;
189 pid_t pid = fork();
190 if (pid < 0)
191 goto error;
192 if (pid > 0) {
193 close(pipefds[0]);
194 if (dup2(pipefds[1], fileno(stdout)) < 0)
195 goto error;
196 if (isatty(fileno(stderr))) {
197 if (dup2(pipefds[1], fileno(stderr)) < 0)
198 goto error;
199 }
200 close(pipefds[1]);
201 pagerpid = pid;
202 return pid;
203 } else {
204 dup2(pipefds[0], fileno(stdin));
205 close(pipefds[0]);
206 close(pipefds[1]);
207
208 int r =
209 execle("/bin/sh", "/bin/sh", "-c", pagercmd, NULL, envp);
210 if (r < 0) {
211 abortmsgerrno("cannot start pager '%s'", pagercmd);
212 }
213 return 0;
176 return 0;
214 }
177 }
215
216 error:
217 close(pipefds[0]);
218 close(pipefds[1]);
219 abortmsgerrno("failed to prepare pager");
220 return 0;
221 }
222
223 void waitpager(void)
224 {
225 if (pagerpid == 0)
226 return;
227
228 /* close output streams to notify the pager its input ends */
229 fclose(stdout);
230 fclose(stderr);
231 while (1) {
232 pid_t ret = waitpid(pagerpid, NULL, 0);
233 if (ret == -1 && errno == EINTR)
234 continue;
235 break;
236 }
237 }
General Comments 0
You need to be logged in to leave comments. Login now