signals.c revision 362181
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#define apr_sigwait(a,b) sigwait((a),(b)) 33#endif 34 35APR_DECLARE(apr_status_t) apr_proc_kill(apr_proc_t *proc, int signum) 36{ 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_OS2_STATUS(DosSendSignalException(proc->pid, 44 XCPT_SIGNAL_BREAK)); 45 } 46#endif /* OS2 */ 47 48 if (kill(proc->pid, signum) == -1) { 49 return errno; 50 } 51 52 return APR_SUCCESS; 53} 54 55 56#if APR_HAVE_SIGACTION 57 58#if defined(__NetBSD__) || defined(DARWIN) 59static 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 */ 74APR_DECLARE(apr_sigfunc_t *) apr_signal(int signo, apr_sigfunc_t * func) 75{ 76 struct sigaction act, oact; 77 78 act.sa_handler = func; 79 sigemptyset(&act.sa_mask); 80 act.sa_flags = 0; 81#ifdef SA_INTERRUPT /* SunOS */ 82 act.sa_flags |= SA_INTERRUPT; 83#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 if (sigaction(signo, &act, &oact) < 0) 104 return SIG_ERR; 105 return oact.sa_handler; 106} 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 114void apr_signal_init(apr_pool_t *pglobal) 115{ 116} 117const char *apr_signal_description_get(int signum) 118{ 119 return (signum >= 0) ? sys_siglist[signum] : "unknown signal (number)"; 120} 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 136static 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 148void 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 262const 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 274static void remove_sync_sigs(sigset_t *sig_mask) 275{ 276#ifdef SIGABRT 277 sigdelset(sig_mask, SIGABRT); 278#endif 279#ifdef SIGBUS 280 sigdelset(sig_mask, SIGBUS); 281#endif 282#ifdef SIGEMT 283 sigdelset(sig_mask, SIGEMT); 284#endif 285#ifdef SIGFPE 286 sigdelset(sig_mask, SIGFPE); 287#endif 288#ifdef SIGILL 289 sigdelset(sig_mask, SIGILL); 290#endif 291#ifdef SIGIOT 292 sigdelset(sig_mask, SIGIOT); 293#endif 294#ifdef SIGPIPE 295 sigdelset(sig_mask, SIGPIPE); 296#endif 297#ifdef SIGSEGV 298 sigdelset(sig_mask, SIGSEGV); 299#endif 300#ifdef SIGSYS 301 sigdelset(sig_mask, SIGSYS); 302#endif 303#ifdef SIGTRAP 304 sigdelset(sig_mask, SIGTRAP); 305#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} 312 313APR_DECLARE(apr_status_t) apr_signal_thread(int(*signal_handler)(int signum)) 314{ 315 sigset_t sig_mask; 316#if APR_HAVE_SIGWAIT 317 int (*sig_func)(int signum) = (int (*)(int))signal_handler; 318#endif 319 320 /* This thread will be the one responsible for handling signals */ 321 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#ifdef SIGKILL 328 sigdelset(&sig_mask, SIGKILL); 329#endif 330#ifdef SIGSTOP 331 sigdelset(&sig_mask, SIGSTOP); 332#endif 333#ifdef SIGCONT 334 sigdelset(&sig_mask, SIGCONT); 335#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 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 while (1) { 374#if APR_HAVE_SIGWAIT 375 int signal_received; 376 377 if (apr_sigwait(&sig_mask, &signal_received) != 0) 378 { 379 /* handle sigwait() error here */ 380 } 381 382 if (sig_func(signal_received) == 1) { 383 return APR_SUCCESS; 384 } 385#elif HAVE_SIGSUSPEND 386 sigsuspend(&sig_mask); 387#else 388#error No apr_sigwait() and no sigsuspend() 389#endif 390 } 391} 392 393APR_DECLARE(apr_status_t) apr_setup_signal_thread(void) 394{ 395 sigset_t sig_mask; 396 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 sigfillset(&sig_mask); 411 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 if ((rv = pthread_sigmask(SIG_SETMASK, &sig_mask, NULL)) != 0) { 419#ifdef HAVE_ZOS_PTHREADS 420 rv = errno; 421#endif 422 } 423#endif 424 return rv; 425} 426 427#endif /* APR_HAS_THREADS && ... */ 428 429APR_DECLARE(apr_status_t) apr_signal_block(int signum) 430{ 431#if APR_HAVE_SIGACTION 432 sigset_t sig_mask; 433 int rv; 434 435 sigemptyset(&sig_mask); 436 437 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 if ((rv = pthread_sigmask(SIG_BLOCK, &sig_mask, NULL)) != 0) { 445#ifdef HAVE_ZOS_PTHREADS 446 rv = errno; 447#endif 448 } 449#endif 450 return rv; 451#else 452 return APR_ENOTIMPL; 453#endif 454} 455 456APR_DECLARE(apr_status_t) apr_signal_unblock(int signum) 457{ 458#if APR_HAVE_SIGACTION 459 sigset_t sig_mask; 460 int rv; 461 462 sigemptyset(&sig_mask); 463 464 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 if ((rv = pthread_sigmask(SIG_UNBLOCK, &sig_mask, NULL)) != 0) { 472#ifdef HAVE_ZOS_PTHREADS 473 rv = errno; 474#endif 475 } 476#endif 477 return rv; 478#else 479 return APR_ENOTIMPL; 480#endif 481} 482