/src/httpd/srclib/apr/threadproc/unix/signals.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Licensed to the Apache Software Foundation (ASF) under one or more |
2 | | * contributor license agreements. See the NOTICE file distributed with |
3 | | * this work for additional information regarding copyright ownership. |
4 | | * The ASF licenses this file to You under the Apache License, Version 2.0 |
5 | | * (the "License"); you may not use this file except in compliance with |
6 | | * the License. You may obtain a copy of the License at |
7 | | * |
8 | | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | | * |
10 | | * Unless required by applicable law or agreed to in writing, software |
11 | | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | | * See the License for the specific language governing permissions and |
14 | | * limitations under the License. |
15 | | */ |
16 | | |
17 | | #define INCL_DOSEXCEPTIONS /* for OS2 */ |
18 | | #include "apr_arch_threadproc.h" |
19 | | #include "apr_private.h" |
20 | | #include "apr_pools.h" |
21 | | #include "apr_signal.h" |
22 | | #include "apr_strings.h" |
23 | | |
24 | | #include <assert.h> |
25 | | #if APR_HAS_THREADS && APR_HAVE_PTHREAD_H |
26 | | #include <pthread.h> |
27 | | #endif |
28 | | |
29 | | #ifdef SIGWAIT_TAKES_ONE_ARG |
30 | | #define apr_sigwait(a,b) ((*(b)=sigwait((a)))<0?-1:0) |
31 | | #else |
32 | 0 | #define apr_sigwait(a,b) sigwait((a),(b)) |
33 | | #endif |
34 | | |
35 | | APR_DECLARE(apr_status_t) apr_proc_kill(apr_proc_t *proc, int signum) |
36 | 0 | { |
37 | | #ifdef OS2 |
38 | | /* SIGTERM's don't work too well in OS/2 (only affects other EMX |
39 | | * programs). CGIs may not be, esp. REXX scripts, so use a native |
40 | | * call instead |
41 | | */ |
42 | | if (signum == SIGTERM) { |
43 | | return APR_FROM_OS_ERROR(DosSendSignalException(proc->pid, |
44 | | XCPT_SIGNAL_BREAK)); |
45 | | } |
46 | | #endif /* OS2 */ |
47 | |
|
48 | 0 | if (kill(proc->pid, signum) == -1) { |
49 | 0 | return errno; |
50 | 0 | } |
51 | | |
52 | 0 | return APR_SUCCESS; |
53 | 0 | } |
54 | | |
55 | | |
56 | | #if APR_HAVE_SIGACTION |
57 | | |
58 | | #if defined(__NetBSD__) || defined(DARWIN) |
59 | | static void avoid_zombies(int signo) |
60 | | { |
61 | | int exit_status; |
62 | | |
63 | | while (waitpid(-1, &exit_status, WNOHANG) > 0) { |
64 | | /* do nothing */ |
65 | | } |
66 | | } |
67 | | #endif /* DARWIN */ |
68 | | |
69 | | /* |
70 | | * Replace standard signal() with the more reliable sigaction equivalent |
71 | | * from W. Richard Stevens' "Advanced Programming in the UNIX Environment" |
72 | | * (the version that does not automatically restart system calls). |
73 | | */ |
74 | | APR_DECLARE(apr_sigfunc_t *) apr_signal(int signo, apr_sigfunc_t * func) |
75 | 0 | { |
76 | 0 | struct sigaction act, oact; |
77 | |
|
78 | 0 | act.sa_handler = func; |
79 | 0 | sigemptyset(&act.sa_mask); |
80 | 0 | act.sa_flags = 0; |
81 | 0 | #ifdef SA_INTERRUPT /* SunOS */ |
82 | 0 | act.sa_flags |= SA_INTERRUPT; |
83 | 0 | #endif |
84 | | #if defined(__osf__) && defined(__alpha) |
85 | | /* XXX jeff thinks this should be enabled whenever SA_NOCLDWAIT is defined */ |
86 | | |
87 | | /* this is required on Tru64 to cause child processes to |
88 | | * disappear gracefully - XPG4 compatible |
89 | | */ |
90 | | if ((signo == SIGCHLD) && (func == SIG_IGN)) { |
91 | | act.sa_flags |= SA_NOCLDWAIT; |
92 | | } |
93 | | #endif |
94 | | #if defined(__NetBSD__) || defined(DARWIN) |
95 | | /* ignoring SIGCHLD or leaving the default disposition doesn't avoid zombies, |
96 | | * and there is no SA_NOCLDWAIT flag, so catch the signal and reap status in |
97 | | * the handler to avoid zombies |
98 | | */ |
99 | | if ((signo == SIGCHLD) && (func == SIG_IGN)) { |
100 | | act.sa_handler = avoid_zombies; |
101 | | } |
102 | | #endif |
103 | 0 | if (sigaction(signo, &act, &oact) < 0) |
104 | 0 | return SIG_ERR; |
105 | 0 | return oact.sa_handler; |
106 | 0 | } |
107 | | |
108 | | #endif /* HAVE_SIGACTION */ |
109 | | |
110 | | /* AC_DECL_SYS_SIGLIST defines either of these symbols depending |
111 | | * on the version of autoconf used. */ |
112 | | #if defined(SYS_SIGLIST_DECLARED) || HAVE_DECL_SYS_SIGLIST |
113 | | |
114 | | void apr_signal_init(apr_pool_t *pglobal) |
115 | 0 | { |
116 | 0 | } |
117 | | const char *apr_signal_description_get(int signum) |
118 | 0 | { |
119 | 0 | return (signum >= 0) ? sys_siglist[signum] : "unknown signal (number)"; |
120 | 0 | } |
121 | | |
122 | | #else /* !(SYS_SIGLIST_DECLARED || HAVE_DECL_SYS_SIGLIST) */ |
123 | | |
124 | | /* we need to roll our own signal description stuff */ |
125 | | |
126 | | #if defined(NSIG) |
127 | | #define APR_NUMSIG NSIG |
128 | | #elif defined(_NSIG) |
129 | | #define APR_NUMSIG _NSIG |
130 | | #elif defined(__NSIG) |
131 | | #define APR_NUMSIG __NSIG |
132 | | #else |
133 | | #define APR_NUMSIG 33 /* breaks on OS/390 with < 33; 32 is o.k. for most */ |
134 | | #endif |
135 | | |
136 | | static const char *signal_description[APR_NUMSIG]; |
137 | | |
138 | | #define store_desc(index, string) \ |
139 | | do { \ |
140 | | if (index >= APR_NUMSIG) { \ |
141 | | assert(index < APR_NUMSIG); \ |
142 | | } \ |
143 | | else { \ |
144 | | signal_description[index] = string; \ |
145 | | } \ |
146 | | } while (0) |
147 | | |
148 | | void apr_signal_init(apr_pool_t *pglobal) |
149 | | { |
150 | | int sig; |
151 | | |
152 | | store_desc(0, "Signal 0"); |
153 | | |
154 | | #ifdef SIGHUP |
155 | | store_desc(SIGHUP, "Hangup"); |
156 | | #endif |
157 | | #ifdef SIGINT |
158 | | store_desc(SIGINT, "Interrupt"); |
159 | | #endif |
160 | | #ifdef SIGQUIT |
161 | | store_desc(SIGQUIT, "Quit"); |
162 | | #endif |
163 | | #ifdef SIGILL |
164 | | store_desc(SIGILL, "Illegal instruction"); |
165 | | #endif |
166 | | #ifdef SIGTRAP |
167 | | store_desc(SIGTRAP, "Trace/BPT trap"); |
168 | | #endif |
169 | | #ifdef SIGIOT |
170 | | store_desc(SIGIOT, "IOT instruction"); |
171 | | #endif |
172 | | #ifdef SIGABRT |
173 | | store_desc(SIGABRT, "Abort"); |
174 | | #endif |
175 | | #ifdef SIGEMT |
176 | | store_desc(SIGEMT, "Emulator trap"); |
177 | | #endif |
178 | | #ifdef SIGFPE |
179 | | store_desc(SIGFPE, "Arithmetic exception"); |
180 | | #endif |
181 | | #ifdef SIGKILL |
182 | | store_desc(SIGKILL, "Killed"); |
183 | | #endif |
184 | | #ifdef SIGBUS |
185 | | store_desc(SIGBUS, "Bus error"); |
186 | | #endif |
187 | | #ifdef SIGSEGV |
188 | | store_desc(SIGSEGV, "Segmentation fault"); |
189 | | #endif |
190 | | #ifdef SIGSYS |
191 | | store_desc(SIGSYS, "Bad system call"); |
192 | | #endif |
193 | | #ifdef SIGPIPE |
194 | | store_desc(SIGPIPE, "Broken pipe"); |
195 | | #endif |
196 | | #ifdef SIGALRM |
197 | | store_desc(SIGALRM, "Alarm clock"); |
198 | | #endif |
199 | | #ifdef SIGTERM |
200 | | store_desc(SIGTERM, "Terminated"); |
201 | | #endif |
202 | | #ifdef SIGUSR1 |
203 | | store_desc(SIGUSR1, "User defined signal 1"); |
204 | | #endif |
205 | | #ifdef SIGUSR2 |
206 | | store_desc(SIGUSR2, "User defined signal 2"); |
207 | | #endif |
208 | | #ifdef SIGCLD |
209 | | store_desc(SIGCLD, "Child status change"); |
210 | | #endif |
211 | | #ifdef SIGCHLD |
212 | | store_desc(SIGCHLD, "Child status change"); |
213 | | #endif |
214 | | #ifdef SIGPWR |
215 | | store_desc(SIGPWR, "Power-fail restart"); |
216 | | #endif |
217 | | #ifdef SIGWINCH |
218 | | store_desc(SIGWINCH, "Window changed"); |
219 | | #endif |
220 | | #ifdef SIGURG |
221 | | store_desc(SIGURG, "urgent socket condition"); |
222 | | #endif |
223 | | #ifdef SIGPOLL |
224 | | store_desc(SIGPOLL, "Pollable event occurred"); |
225 | | #endif |
226 | | #ifdef SIGIO |
227 | | store_desc(SIGIO, "socket I/O possible"); |
228 | | #endif |
229 | | #ifdef SIGSTOP |
230 | | store_desc(SIGSTOP, "Stopped (signal)"); |
231 | | #endif |
232 | | #ifdef SIGTSTP |
233 | | store_desc(SIGTSTP, "Stopped"); |
234 | | #endif |
235 | | #ifdef SIGCONT |
236 | | store_desc(SIGCONT, "Continued"); |
237 | | #endif |
238 | | #ifdef SIGTTIN |
239 | | store_desc(SIGTTIN, "Stopped (tty input)"); |
240 | | #endif |
241 | | #ifdef SIGTTOU |
242 | | store_desc(SIGTTOU, "Stopped (tty output)"); |
243 | | #endif |
244 | | #ifdef SIGVTALRM |
245 | | store_desc(SIGVTALRM, "virtual timer expired"); |
246 | | #endif |
247 | | #ifdef SIGPROF |
248 | | store_desc(SIGPROF, "profiling timer expired"); |
249 | | #endif |
250 | | #ifdef SIGXCPU |
251 | | store_desc(SIGXCPU, "exceeded cpu limit"); |
252 | | #endif |
253 | | #ifdef SIGXFSZ |
254 | | store_desc(SIGXFSZ, "exceeded file size limit"); |
255 | | #endif |
256 | | |
257 | | for (sig = 0; sig < APR_NUMSIG; ++sig) |
258 | | if (signal_description[sig] == NULL) |
259 | | signal_description[sig] = apr_psprintf(pglobal, "signal #%d", sig); |
260 | | } |
261 | | |
262 | | const char *apr_signal_description_get(int signum) |
263 | | { |
264 | | return |
265 | | (signum >= 0 && signum < APR_NUMSIG) |
266 | | ? signal_description[signum] |
267 | | : "unknown signal (number)"; |
268 | | } |
269 | | |
270 | | #endif /* SYS_SIGLIST_DECLARED || HAVE_DECL_SYS_SIGLIST */ |
271 | | |
272 | | #if APR_HAS_THREADS && (HAVE_SIGSUSPEND || APR_HAVE_SIGWAIT) && !defined(OS2) |
273 | | |
274 | | static void remove_sync_sigs(sigset_t *sig_mask) |
275 | 0 | { |
276 | 0 | #ifdef SIGABRT |
277 | 0 | sigdelset(sig_mask, SIGABRT); |
278 | 0 | #endif |
279 | 0 | #ifdef SIGBUS |
280 | 0 | sigdelset(sig_mask, SIGBUS); |
281 | 0 | #endif |
282 | | #ifdef SIGEMT |
283 | | sigdelset(sig_mask, SIGEMT); |
284 | | #endif |
285 | 0 | #ifdef SIGFPE |
286 | 0 | sigdelset(sig_mask, SIGFPE); |
287 | 0 | #endif |
288 | 0 | #ifdef SIGILL |
289 | 0 | sigdelset(sig_mask, SIGILL); |
290 | 0 | #endif |
291 | 0 | #ifdef SIGIOT |
292 | 0 | sigdelset(sig_mask, SIGIOT); |
293 | 0 | #endif |
294 | 0 | #ifdef SIGPIPE |
295 | 0 | sigdelset(sig_mask, SIGPIPE); |
296 | 0 | #endif |
297 | 0 | #ifdef SIGSEGV |
298 | 0 | sigdelset(sig_mask, SIGSEGV); |
299 | 0 | #endif |
300 | 0 | #ifdef SIGSYS |
301 | 0 | sigdelset(sig_mask, SIGSYS); |
302 | 0 | #endif |
303 | 0 | #ifdef SIGTRAP |
304 | 0 | sigdelset(sig_mask, SIGTRAP); |
305 | 0 | #endif |
306 | | |
307 | | /* the rest of the signals removed from the mask in this function |
308 | | * absolutely must be removed; you cannot block synchronous signals |
309 | | * (requirement of pthreads API) |
310 | | */ |
311 | 0 | } |
312 | | |
313 | | APR_DECLARE(apr_status_t) apr_signal_thread(int(*signal_handler)(int signum)) |
314 | 0 | { |
315 | 0 | sigset_t sig_mask; |
316 | 0 | #if APR_HAVE_SIGWAIT |
317 | 0 | int (*sig_func)(int signum) = (int (*)(int))signal_handler; |
318 | 0 | #endif |
319 | | |
320 | | /* This thread will be the one responsible for handling signals */ |
321 | 0 | sigfillset(&sig_mask); |
322 | | |
323 | | /* On certain platforms, sigwait() returns EINVAL if any of various |
324 | | * unblockable signals are included in the mask. This was first |
325 | | * observed on AIX and Tru64. |
326 | | */ |
327 | 0 | #ifdef SIGKILL |
328 | 0 | sigdelset(&sig_mask, SIGKILL); |
329 | 0 | #endif |
330 | 0 | #ifdef SIGSTOP |
331 | 0 | sigdelset(&sig_mask, SIGSTOP); |
332 | 0 | #endif |
333 | 0 | #ifdef SIGCONT |
334 | 0 | sigdelset(&sig_mask, SIGCONT); |
335 | 0 | #endif |
336 | | #ifdef SIGWAITING |
337 | | sigdelset(&sig_mask, SIGWAITING); |
338 | | #endif |
339 | | |
340 | | /* no synchronous signals should be in the mask passed to sigwait() */ |
341 | 0 | remove_sync_sigs(&sig_mask); |
342 | | |
343 | | /* On AIX (4.3.3, at least), sigwait() won't wake up if the high- |
344 | | * order bit of the second word of flags is turned on. sigdelset() |
345 | | * returns an error when trying to turn this off, so we'll turn it |
346 | | * off manually. |
347 | | * |
348 | | * Note that the private fields differ between 32-bit and 64-bit |
349 | | * and even between _ALL_SOURCE and !_ALL_SOURCE. Except that on |
350 | | * AIX 4.3 32-bit builds and 64-bit builds use the same definition. |
351 | | * |
352 | | * Applicable AIX fixes such that this is no longer needed: |
353 | | * |
354 | | * APAR IY23096 for AIX 51B, fix included in AIX 51C, and |
355 | | * APAR IY24162 for 43X. |
356 | | */ |
357 | | #if defined(_AIX) |
358 | | #if defined(__64BIT__) && defined(_AIXVERSION_510) |
359 | | #ifdef _ALL_SOURCE |
360 | | sig_mask.ss_set[3] &= 0x7FFFFFFF; |
361 | | #else /* not _ALL_SOURCE */ |
362 | | sig_mask.__ss_set[3] &= 0x7FFFFFFF; |
363 | | #endif |
364 | | #else /* not 64-bit build, or 64-bit build on 4.3 */ |
365 | | #ifdef _ALL_SOURCE |
366 | | sig_mask.hisigs &= 0x7FFFFFFF; |
367 | | #else /* not _ALL_SOURCE */ |
368 | | sig_mask.__hisigs &= 0x7FFFFFFF; |
369 | | #endif |
370 | | #endif |
371 | | #endif /* _AIX */ |
372 | |
|
373 | 0 | while (1) { |
374 | 0 | #if APR_HAVE_SIGWAIT |
375 | 0 | int signal_received; |
376 | |
|
377 | 0 | if (apr_sigwait(&sig_mask, &signal_received) != 0) |
378 | 0 | { |
379 | | /* handle sigwait() error here */ |
380 | 0 | } |
381 | |
|
382 | 0 | if (sig_func(signal_received) == 1) { |
383 | 0 | return APR_SUCCESS; |
384 | 0 | } |
385 | | #elif HAVE_SIGSUSPEND |
386 | | sigsuspend(&sig_mask); |
387 | | #else |
388 | | #error No apr_sigwait() and no sigsuspend() |
389 | | #endif |
390 | 0 | } |
391 | 0 | } |
392 | | |
393 | | APR_DECLARE(apr_status_t) apr_setup_signal_thread(void) |
394 | 0 | { |
395 | 0 | sigset_t sig_mask; |
396 | 0 | int rv; |
397 | | |
398 | | /* All threads should mask out signals to be handled by |
399 | | * the thread doing sigwait(). |
400 | | * |
401 | | * No thread should ever block synchronous signals. |
402 | | * See the Solaris man page for pthread_sigmask() for |
403 | | * some information. Solaris chooses to knock out such |
404 | | * processes when a blocked synchronous signal is |
405 | | * delivered, skipping any registered signal handler. |
406 | | * AIX doesn't call a signal handler either. At least |
407 | | * one level of linux+glibc does call the handler even |
408 | | * when the synchronous signal is blocked. |
409 | | */ |
410 | 0 | sigfillset(&sig_mask); |
411 | 0 | remove_sync_sigs(&sig_mask); |
412 | |
|
413 | | #if defined(SIGPROCMASK_SETS_THREAD_MASK) || ! APR_HAS_THREADS |
414 | | if ((rv = sigprocmask(SIG_SETMASK, &sig_mask, NULL)) != 0) { |
415 | | rv = errno; |
416 | | } |
417 | | #else |
418 | 0 | if ((rv = pthread_sigmask(SIG_SETMASK, &sig_mask, NULL)) != 0) { |
419 | | #ifdef HAVE_ZOS_PTHREADS |
420 | | rv = errno; |
421 | | #endif |
422 | 0 | } |
423 | 0 | #endif |
424 | 0 | return rv; |
425 | 0 | } |
426 | | |
427 | | #endif /* APR_HAS_THREADS && ... */ |
428 | | |
429 | | APR_DECLARE(apr_status_t) apr_signal_block(int signum) |
430 | 0 | { |
431 | 0 | #if APR_HAVE_SIGACTION |
432 | 0 | sigset_t sig_mask; |
433 | 0 | int rv; |
434 | |
|
435 | 0 | sigemptyset(&sig_mask); |
436 | |
|
437 | 0 | sigaddset(&sig_mask, signum); |
438 | |
|
439 | | #if defined(SIGPROCMASK_SETS_THREAD_MASK) || ! APR_HAS_THREADS |
440 | | if ((rv = sigprocmask(SIG_BLOCK, &sig_mask, NULL)) != 0) { |
441 | | rv = errno; |
442 | | } |
443 | | #else |
444 | 0 | if ((rv = pthread_sigmask(SIG_BLOCK, &sig_mask, NULL)) != 0) { |
445 | | #ifdef HAVE_ZOS_PTHREADS |
446 | | rv = errno; |
447 | | #endif |
448 | 0 | } |
449 | 0 | #endif |
450 | 0 | return rv; |
451 | | #else |
452 | | return APR_ENOTIMPL; |
453 | | #endif |
454 | 0 | } |
455 | | |
456 | | APR_DECLARE(apr_status_t) apr_signal_unblock(int signum) |
457 | 0 | { |
458 | 0 | #if APR_HAVE_SIGACTION |
459 | 0 | sigset_t sig_mask; |
460 | 0 | int rv; |
461 | |
|
462 | 0 | sigemptyset(&sig_mask); |
463 | |
|
464 | 0 | sigaddset(&sig_mask, signum); |
465 | |
|
466 | | #if defined(SIGPROCMASK_SETS_THREAD_MASK) || ! APR_HAS_THREADS |
467 | | if ((rv = sigprocmask(SIG_UNBLOCK, &sig_mask, NULL)) != 0) { |
468 | | rv = errno; |
469 | | } |
470 | | #else |
471 | 0 | if ((rv = pthread_sigmask(SIG_UNBLOCK, &sig_mask, NULL)) != 0) { |
472 | | #ifdef HAVE_ZOS_PTHREADS |
473 | | rv = errno; |
474 | | #endif |
475 | 0 | } |
476 | 0 | #endif |
477 | 0 | return rv; |
478 | | #else |
479 | | return APR_ENOTIMPL; |
480 | | #endif |
481 | 0 | } |