1
/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
* you may not use this file except in compliance with the License.
6
* You may obtain a copy of the License at
8
* http://www.apache.org/licenses/LICENSE-2.0
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.
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"
25
#if APR_HAS_THREADS && APR_HAVE_PTHREAD_H
29
#ifdef SIGWAIT_TAKES_ONE_ARG
30
#define apr_sigwait(a,b) ((*(b)=sigwait((a)))<0?-1:0)
32
#define apr_sigwait(a,b) sigwait((a),(b))
35
APR_DECLARE(apr_status_t) apr_proc_kill(apr_proc_t *proc, int signum)
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
42
if (signum == SIGTERM) {
43
return APR_OS2_STATUS(DosSendSignalException(proc->pid,
48
if (kill(proc->pid, signum) == -1) {
56
#if APR_HAVE_SIGACTION
59
static void avoid_zombies(int signo)
63
while (waitpid(-1, &exit_status, WNOHANG) > 0) {
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).
74
APR_DECLARE(apr_sigfunc_t *) apr_signal(int signo, apr_sigfunc_t * func)
76
struct sigaction act, oact;
78
act.sa_handler = func;
79
sigemptyset(&act.sa_mask);
81
#ifdef SA_INTERRUPT /* SunOS */
82
act.sa_flags |= SA_INTERRUPT;
84
#if defined(__osf__) && defined(__alpha)
85
/* XXX jeff thinks this should be enabled whenever SA_NOCLDWAIT is defined */
87
/* this is required on Tru64 to cause child processes to
88
* disappear gracefully - XPG4 compatible
90
if ((signo == SIGCHLD) && (func == SIG_IGN)) {
91
act.sa_flags |= SA_NOCLDWAIT;
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
99
if ((signo == SIGCHLD) && (func == SIG_IGN)) {
100
act.sa_handler = avoid_zombies;
103
if (sigaction(signo, &act, &oact) < 0)
105
return oact.sa_handler;
108
#endif /* HAVE_SIGACTION */
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
114
void apr_signal_init(apr_pool_t *pglobal)
117
const char *apr_signal_description_get(int signum)
119
return sys_siglist[signum];
122
#else /* !(SYS_SIGLIST_DECLARED || HAVE_DECL_SYS_SIGLIST) */
124
/* we need to roll our own signal description stuff */
127
#define APR_NUMSIG NSIG
129
#define APR_NUMSIG _NSIG
130
#elif defined(__NSIG)
131
#define APR_NUMSIG __NSIG
133
#define APR_NUMSIG 33 /* breaks on OS/390 with < 33; 32 is o.k. for most */
136
static const char *signal_description[APR_NUMSIG];
138
#define store_desc(index, string) \
140
if (index >= APR_NUMSIG) { \
141
assert(index < APR_NUMSIG); \
144
signal_description[index] = string; \
148
void apr_signal_init(apr_pool_t *pglobal)
152
store_desc(0, "Signal 0");
155
store_desc(SIGHUP, "Hangup");
158
store_desc(SIGINT, "Interrupt");
161
store_desc(SIGQUIT, "Quit");
164
store_desc(SIGILL, "Illegal instruction");
167
store_desc(SIGTRAP, "Trace/BPT trap");
170
store_desc(SIGIOT, "IOT instruction");
173
store_desc(SIGABRT, "Abort");
176
store_desc(SIGEMT, "Emulator trap");
179
store_desc(SIGFPE, "Arithmetic exception");
182
store_desc(SIGKILL, "Killed");
185
store_desc(SIGBUS, "Bus error");
188
store_desc(SIGSEGV, "Segmentation fault");
191
store_desc(SIGSYS, "Bad system call");
194
store_desc(SIGPIPE, "Broken pipe");
197
store_desc(SIGALRM, "Alarm clock");
200
store_desc(SIGTERM, "Terminated");
203
store_desc(SIGUSR1, "User defined signal 1");
206
store_desc(SIGUSR2, "User defined signal 2");
209
store_desc(SIGCLD, "Child status change");
212
store_desc(SIGCHLD, "Child status change");
215
store_desc(SIGPWR, "Power-fail restart");
218
store_desc(SIGWINCH, "Window changed");
221
store_desc(SIGURG, "urgent socket condition");
224
store_desc(SIGPOLL, "Pollable event occurred");
227
store_desc(SIGIO, "socket I/O possible");
230
store_desc(SIGSTOP, "Stopped (signal)");
233
store_desc(SIGTSTP, "Stopped");
236
store_desc(SIGCONT, "Continued");
239
store_desc(SIGTTIN, "Stopped (tty input)");
242
store_desc(SIGTTOU, "Stopped (tty output)");
245
store_desc(SIGVTALRM, "virtual timer expired");
248
store_desc(SIGPROF, "profiling timer expired");
251
store_desc(SIGXCPU, "exceeded cpu limit");
254
store_desc(SIGXFSZ, "exceeded file size limit");
257
for (sig = 0; sig < APR_NUMSIG; ++sig)
258
if (signal_description[sig] == NULL)
259
signal_description[sig] = apr_psprintf(pglobal, "signal #%d", sig);
262
const char *apr_signal_description_get(int signum)
266
? signal_description[signum]
267
: "unknown signal (number)";
270
#endif /* SYS_SIGLIST_DECLARED || HAVE_DECL_SYS_SIGLIST */
272
#if APR_HAS_THREADS && (HAVE_SIGSUSPEND || APR_HAVE_SIGWAIT) && !defined(OS2)
274
static void remove_sync_sigs(sigset_t *sig_mask)
277
sigdelset(sig_mask, SIGABRT);
280
sigdelset(sig_mask, SIGBUS);
283
sigdelset(sig_mask, SIGEMT);
286
sigdelset(sig_mask, SIGFPE);
289
sigdelset(sig_mask, SIGILL);
292
sigdelset(sig_mask, SIGIOT);
295
sigdelset(sig_mask, SIGPIPE);
298
sigdelset(sig_mask, SIGSEGV);
301
sigdelset(sig_mask, SIGSYS);
304
sigdelset(sig_mask, SIGTRAP);
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)
311
* SIGUSR2 is being removed from the mask for the convenience of
312
* Purify users (Solaris, HP-UX, SGI) since Purify uses SIGUSR2
315
sigdelset(sig_mask, SIGUSR2);
319
APR_DECLARE(apr_status_t) apr_signal_thread(int(*signal_handler)(int signum))
323
int (*sig_func)(int signum) = (int (*)(int))signal_handler;
326
/* This thread will be the one responsible for handling signals */
327
sigfillset(&sig_mask);
329
/* On certain platforms, sigwait() returns EINVAL if any of various
330
* unblockable signals are included in the mask. This was first
331
* observed on AIX and Tru64.
334
sigdelset(&sig_mask, SIGKILL);
337
sigdelset(&sig_mask, SIGSTOP);
340
sigdelset(&sig_mask, SIGCONT);
343
sigdelset(&sig_mask, SIGWAITING);
346
/* no synchronous signals should be in the mask passed to sigwait() */
347
remove_sync_sigs(&sig_mask);
349
/* On AIX (4.3.3, at least), sigwait() won't wake up if the high-
350
* order bit of the second word of flags is turned on. sigdelset()
351
* returns an error when trying to turn this off, so we'll turn it
354
* Note that the private fields differ between 32-bit and 64-bit
355
* and even between _ALL_SOURCE and !_ALL_SOURCE. Except that on
356
* AIX 4.3 32-bit builds and 64-bit builds use the same definition.
358
* Applicable AIX fixes such that this is no longer needed:
360
* APAR IY23096 for AIX 51B, fix included in AIX 51C, and
361
* APAR IY24162 for 43X.
364
#if defined(__64BIT__) && defined(_AIXVERSION_510)
366
sig_mask.ss_set[3] &= 0x7FFFFFFF;
367
#else /* not _ALL_SOURCE */
368
sig_mask.__ss_set[3] &= 0x7FFFFFFF;
370
#else /* not 64-bit build, or 64-bit build on 4.3 */
372
sig_mask.hisigs &= 0x7FFFFFFF;
373
#else /* not _ALL_SOURCE */
374
sig_mask.__hisigs &= 0x7FFFFFFF;
383
if (apr_sigwait(&sig_mask, &signal_received) != 0)
385
/* handle sigwait() error here */
388
if (sig_func(signal_received) == 1) {
391
#elif HAVE_SIGSUSPEND
392
sigsuspend(&sig_mask);
394
#error No apr_sigwait() and no sigsuspend()
399
APR_DECLARE(apr_status_t) apr_setup_signal_thread(void)
404
/* All threads should mask out signals to be handled by
405
* the thread doing sigwait().
407
* No thread should ever block synchronous signals.
408
* See the Solaris man page for pthread_sigmask() for
409
* some information. Solaris chooses to knock out such
410
* processes when a blocked synchronous signal is
411
* delivered, skipping any registered signal handler.
412
* AIX doesn't call a signal handler either. At least
413
* one level of linux+glibc does call the handler even
414
* when the synchronous signal is blocked.
416
sigfillset(&sig_mask);
417
remove_sync_sigs(&sig_mask);
419
#if defined(SIGPROCMASK_SETS_THREAD_MASK) || ! APR_HAS_THREADS
420
if ((rv = sigprocmask(SIG_SETMASK, &sig_mask, NULL)) != 0) {
424
if ((rv = pthread_sigmask(SIG_SETMASK, &sig_mask, NULL)) != 0) {
425
#ifdef PTHREAD_SETS_ERRNO
433
#endif /* APR_HAS_THREADS && ... */
435
APR_DECLARE(apr_status_t) apr_signal_block(int signum)
437
#if APR_HAVE_SIGACTION
441
sigemptyset(&sig_mask);
443
sigaddset(&sig_mask, signum);
445
#if defined(SIGPROCMASK_SETS_THREAD_MASK) || ! APR_HAS_THREADS
446
if ((rv = sigprocmask(SIG_BLOCK, &sig_mask, NULL)) != 0) {
450
if ((rv = pthread_sigmask(SIG_BLOCK, &sig_mask, NULL)) != 0) {
451
#ifdef PTHREAD_SETS_ERRNO
462
APR_DECLARE(apr_status_t) apr_signal_unblock(int signum)
464
#if APR_HAVE_SIGACTION
468
sigemptyset(&sig_mask);
470
sigaddset(&sig_mask, signum);
472
#if defined(SIGPROCMASK_SETS_THREAD_MASK) || ! APR_HAS_THREADS
473
if ((rv = sigprocmask(SIG_UNBLOCK, &sig_mask, NULL)) != 0) {
477
if ((rv = pthread_sigmask(SIG_UNBLOCK, &sig_mask, NULL)) != 0) {
478
#ifdef PTHREAD_SETS_ERRNO