23 static pid_t peerpid = 0; |
23 static pid_t peerpid = 0; |
24 |
24 |
25 static void forwardsignal(int sig) |
25 static void forwardsignal(int sig) |
26 { |
26 { |
27 assert(peerpid > 0); |
27 assert(peerpid > 0); |
28 if (kill(peerpid, sig) < 0) |
28 if (kill(peerpid, sig) < 0) { |
29 abortmsgerrno("cannot kill %d", peerpid); |
29 abortmsgerrno("cannot kill %d", peerpid); |
|
30 } |
30 debugmsg("forward signal %d", sig); |
31 debugmsg("forward signal %d", sig); |
31 } |
32 } |
32 |
33 |
33 static void forwardsignaltogroup(int sig) |
34 static void forwardsignaltogroup(int sig) |
34 { |
35 { |
35 /* prefer kill(-pgid, sig), fallback to pid if pgid is invalid */ |
36 /* prefer kill(-pgid, sig), fallback to pid if pgid is invalid */ |
36 pid_t killpid = peerpgid > 1 ? -peerpgid : peerpid; |
37 pid_t killpid = peerpgid > 1 ? -peerpgid : peerpid; |
37 if (kill(killpid, sig) < 0) |
38 if (kill(killpid, sig) < 0) { |
38 abortmsgerrno("cannot kill %d", killpid); |
39 abortmsgerrno("cannot kill %d", killpid); |
|
40 } |
39 debugmsg("forward signal %d to %d", sig, killpid); |
41 debugmsg("forward signal %d to %d", sig, killpid); |
40 } |
42 } |
41 |
43 |
42 static void handlestopsignal(int sig) |
44 static void handlestopsignal(int sig) |
43 { |
45 { |
44 sigset_t unblockset, oldset; |
46 sigset_t unblockset, oldset; |
45 struct sigaction sa, oldsa; |
47 struct sigaction sa, oldsa; |
46 if (sigemptyset(&unblockset) < 0) |
48 if (sigemptyset(&unblockset) < 0) { |
47 goto error; |
49 goto error; |
48 if (sigaddset(&unblockset, sig) < 0) |
50 } |
49 goto error; |
51 if (sigaddset(&unblockset, sig) < 0) { |
|
52 goto error; |
|
53 } |
50 memset(&sa, 0, sizeof(sa)); |
54 memset(&sa, 0, sizeof(sa)); |
51 sa.sa_handler = SIG_DFL; |
55 sa.sa_handler = SIG_DFL; |
52 sa.sa_flags = SA_RESTART; |
56 sa.sa_flags = SA_RESTART; |
53 if (sigemptyset(&sa.sa_mask) < 0) |
57 if (sigemptyset(&sa.sa_mask) < 0) { |
54 goto error; |
58 goto error; |
|
59 } |
55 |
60 |
56 forwardsignal(sig); |
61 forwardsignal(sig); |
57 if (raise(sig) < 0) /* resend to self */ |
62 if (raise(sig) < 0) { /* resend to self */ |
58 goto error; |
63 goto error; |
59 if (sigaction(sig, &sa, &oldsa) < 0) |
64 } |
60 goto error; |
65 if (sigaction(sig, &sa, &oldsa) < 0) { |
61 if (sigprocmask(SIG_UNBLOCK, &unblockset, &oldset) < 0) |
66 goto error; |
62 goto error; |
67 } |
|
68 if (sigprocmask(SIG_UNBLOCK, &unblockset, &oldset) < 0) { |
|
69 goto error; |
|
70 } |
63 /* resent signal will be handled before sigprocmask() returns */ |
71 /* resent signal will be handled before sigprocmask() returns */ |
64 if (sigprocmask(SIG_SETMASK, &oldset, NULL) < 0) |
72 if (sigprocmask(SIG_SETMASK, &oldset, NULL) < 0) { |
65 goto error; |
73 goto error; |
66 if (sigaction(sig, &oldsa, NULL) < 0) |
74 } |
67 goto error; |
75 if (sigaction(sig, &oldsa, NULL) < 0) { |
|
76 goto error; |
|
77 } |
68 return; |
78 return; |
69 |
79 |
70 error: |
80 error: |
71 abortmsgerrno("failed to handle stop signal"); |
81 abortmsgerrno("failed to handle stop signal"); |
72 } |
82 } |
73 |
83 |
74 static void handlechildsignal(int sig UNUSED_) |
84 static void handlechildsignal(int sig UNUSED_) |
75 { |
85 { |
76 if (peerpid == 0 || pagerpid == 0) |
86 if (peerpid == 0 || pagerpid == 0) { |
77 return; |
87 return; |
|
88 } |
78 /* if pager exits, notify the server with SIGPIPE immediately. |
89 /* if pager exits, notify the server with SIGPIPE immediately. |
79 * otherwise the server won't get SIGPIPE if it does not write |
90 * otherwise the server won't get SIGPIPE if it does not write |
80 * anything. (issue5278) */ |
91 * anything. (issue5278) */ |
81 if (waitpid(pagerpid, NULL, WNOHANG) == pagerpid) |
92 if (waitpid(pagerpid, NULL, WNOHANG) == pagerpid) { |
82 kill(peerpid, SIGPIPE); |
93 kill(peerpid, SIGPIPE); |
|
94 } |
83 } |
95 } |
84 |
96 |
85 void setupsignalhandler(pid_t pid, pid_t pgid) |
97 void setupsignalhandler(pid_t pid, pid_t pgid) |
86 { |
98 { |
87 if (pid <= 0) |
99 if (pid <= 0) { |
88 return; |
100 return; |
|
101 } |
89 peerpid = pid; |
102 peerpid = pid; |
90 peerpgid = (pgid <= 1 ? 0 : pgid); |
103 peerpgid = (pgid <= 1 ? 0 : pgid); |
91 |
104 |
92 struct sigaction sa; |
105 struct sigaction sa; |
93 memset(&sa, 0, sizeof(sa)); |
106 memset(&sa, 0, sizeof(sa)); |
96 * - SIGHUP: usually generated by the kernel, when termination of a |
109 * - SIGHUP: usually generated by the kernel, when termination of a |
97 * process causes that process group to become orphaned |
110 * process causes that process group to become orphaned |
98 * - SIGINT: usually generated by the terminal */ |
111 * - SIGINT: usually generated by the terminal */ |
99 sa.sa_handler = forwardsignaltogroup; |
112 sa.sa_handler = forwardsignaltogroup; |
100 sa.sa_flags = SA_RESTART; |
113 sa.sa_flags = SA_RESTART; |
101 if (sigemptyset(&sa.sa_mask) < 0) |
114 if (sigemptyset(&sa.sa_mask) < 0) { |
102 goto error; |
115 goto error; |
103 if (sigaction(SIGHUP, &sa, NULL) < 0) |
116 } |
104 goto error; |
117 if (sigaction(SIGHUP, &sa, NULL) < 0) { |
105 if (sigaction(SIGINT, &sa, NULL) < 0) |
118 goto error; |
106 goto error; |
119 } |
|
120 if (sigaction(SIGINT, &sa, NULL) < 0) { |
|
121 goto error; |
|
122 } |
107 |
123 |
108 /* terminate frontend by double SIGTERM in case of server freeze */ |
124 /* terminate frontend by double SIGTERM in case of server freeze */ |
109 sa.sa_handler = forwardsignal; |
125 sa.sa_handler = forwardsignal; |
110 sa.sa_flags |= SA_RESETHAND; |
126 sa.sa_flags |= SA_RESETHAND; |
111 if (sigaction(SIGTERM, &sa, NULL) < 0) |
127 if (sigaction(SIGTERM, &sa, NULL) < 0) { |
112 goto error; |
128 goto error; |
|
129 } |
113 |
130 |
114 /* notify the worker about window resize events */ |
131 /* notify the worker about window resize events */ |
115 sa.sa_flags = SA_RESTART; |
132 sa.sa_flags = SA_RESTART; |
116 if (sigaction(SIGWINCH, &sa, NULL) < 0) |
133 if (sigaction(SIGWINCH, &sa, NULL) < 0) { |
117 goto error; |
134 goto error; |
|
135 } |
118 /* forward user-defined signals */ |
136 /* forward user-defined signals */ |
119 if (sigaction(SIGUSR1, &sa, NULL) < 0) |
137 if (sigaction(SIGUSR1, &sa, NULL) < 0) { |
120 goto error; |
138 goto error; |
121 if (sigaction(SIGUSR2, &sa, NULL) < 0) |
139 } |
122 goto error; |
140 if (sigaction(SIGUSR2, &sa, NULL) < 0) { |
|
141 goto error; |
|
142 } |
123 /* propagate job control requests to worker */ |
143 /* propagate job control requests to worker */ |
124 sa.sa_handler = forwardsignal; |
144 sa.sa_handler = forwardsignal; |
125 sa.sa_flags = SA_RESTART; |
145 sa.sa_flags = SA_RESTART; |
126 if (sigaction(SIGCONT, &sa, NULL) < 0) |
146 if (sigaction(SIGCONT, &sa, NULL) < 0) { |
127 goto error; |
147 goto error; |
|
148 } |
128 sa.sa_handler = handlestopsignal; |
149 sa.sa_handler = handlestopsignal; |
129 sa.sa_flags = SA_RESTART; |
150 sa.sa_flags = SA_RESTART; |
130 if (sigaction(SIGTSTP, &sa, NULL) < 0) |
151 if (sigaction(SIGTSTP, &sa, NULL) < 0) { |
131 goto error; |
152 goto error; |
|
153 } |
132 /* get notified when pager exits */ |
154 /* get notified when pager exits */ |
133 sa.sa_handler = handlechildsignal; |
155 sa.sa_handler = handlechildsignal; |
134 sa.sa_flags = SA_RESTART; |
156 sa.sa_flags = SA_RESTART; |
135 if (sigaction(SIGCHLD, &sa, NULL) < 0) |
157 if (sigaction(SIGCHLD, &sa, NULL) < 0) { |
136 goto error; |
158 goto error; |
|
159 } |
137 |
160 |
138 return; |
161 return; |
139 |
162 |
140 error: |
163 error: |
141 abortmsgerrno("failed to set up signal handlers"); |
164 abortmsgerrno("failed to set up signal handlers"); |
145 { |
168 { |
146 struct sigaction sa; |
169 struct sigaction sa; |
147 memset(&sa, 0, sizeof(sa)); |
170 memset(&sa, 0, sizeof(sa)); |
148 sa.sa_handler = SIG_DFL; |
171 sa.sa_handler = SIG_DFL; |
149 sa.sa_flags = SA_RESTART; |
172 sa.sa_flags = SA_RESTART; |
150 if (sigemptyset(&sa.sa_mask) < 0) |
173 if (sigemptyset(&sa.sa_mask) < 0) { |
151 goto error; |
174 goto error; |
152 |
175 } |
153 if (sigaction(SIGHUP, &sa, NULL) < 0) |
176 |
154 goto error; |
177 if (sigaction(SIGHUP, &sa, NULL) < 0) { |
155 if (sigaction(SIGTERM, &sa, NULL) < 0) |
178 goto error; |
156 goto error; |
179 } |
157 if (sigaction(SIGWINCH, &sa, NULL) < 0) |
180 if (sigaction(SIGTERM, &sa, NULL) < 0) { |
158 goto error; |
181 goto error; |
159 if (sigaction(SIGCONT, &sa, NULL) < 0) |
182 } |
160 goto error; |
183 if (sigaction(SIGWINCH, &sa, NULL) < 0) { |
161 if (sigaction(SIGTSTP, &sa, NULL) < 0) |
184 goto error; |
162 goto error; |
185 } |
163 if (sigaction(SIGCHLD, &sa, NULL) < 0) |
186 if (sigaction(SIGCONT, &sa, NULL) < 0) { |
164 goto error; |
187 goto error; |
|
188 } |
|
189 if (sigaction(SIGTSTP, &sa, NULL) < 0) { |
|
190 goto error; |
|
191 } |
|
192 if (sigaction(SIGCHLD, &sa, NULL) < 0) { |
|
193 goto error; |
|
194 } |
165 |
195 |
166 /* ignore Ctrl+C while shutting down to make pager exits cleanly */ |
196 /* ignore Ctrl+C while shutting down to make pager exits cleanly */ |
167 sa.sa_handler = SIG_IGN; |
197 sa.sa_handler = SIG_IGN; |
168 if (sigaction(SIGINT, &sa, NULL) < 0) |
198 if (sigaction(SIGINT, &sa, NULL) < 0) { |
169 goto error; |
199 goto error; |
|
200 } |
170 |
201 |
171 peerpid = 0; |
202 peerpid = 0; |
172 return; |
203 return; |
173 |
204 |
174 error: |
205 error: |