root/Zend/zend_signal.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. zend_signal_handler_defer
  2. zend_signal_handler_unblock
  3. zend_signal_handler
  4. zend_sigaction
  5. zend_signal
  6. zend_signal_register
  7. zend_signal_activate
  8. zend_signal_deactivate
  9. zend_signal_globals_ctor
  10. zend_signal_globals_dtor
  11. zend_signal_startup
  12. zend_signal_shutdown

   1 /*
   2   +----------------------------------------------------------------------+
   3   | Zend Signal Handling                                                 |
   4   +----------------------------------------------------------------------+
   5   | Copyright (c) 2008 The PHP Group                                     |
   6   +----------------------------------------------------------------------+
   7   | This source file is subject to version 3.01 of the PHP license,      |
   8   | that is bundled with this package in the file LICENSE, and is        |
   9   | available through the world-wide-web at the following url:           |
  10   | http://www.php.net/license/3_01.txt                                  |
  11   | If you did not receive a copy of the PHP license and are unable to   |
  12   | obtain it through the world-wide-web, please send a note to          |
  13   | license@php.net so we can mail you a copy immediately.               |
  14   +----------------------------------------------------------------------+
  15   | Authors: Lucas Nealan <lucas@php.net>                                |
  16   |          Arnaud Le Blanc <lbarnaud@php.net>                          |
  17   +----------------------------------------------------------------------+
  18 
  19    This software was contributed to PHP by Facebook Inc. in 2008.
  20 
  21    Future revisions and derivatives of this source code must acknowledge
  22    Facebook Inc. as the original contributor of this module by leaving
  23    this note intact in the source code.
  24 
  25    All other licensing and usage conditions are those of the PHP Group.
  26 */
  27 
  28  /* $Id$ */
  29 
  30 #define _GNU_SOURCE
  31 #include <string.h>
  32 
  33 #include "zend.h"
  34 #include "zend_globals.h"
  35 
  36 #ifdef HAVE_SIGNAL_H
  37 #include <signal.h>
  38 #endif
  39 
  40 #ifdef HAVE_UNISTD_H
  41 #include <unistd.h>
  42 #endif
  43 
  44 #ifdef ZEND_SIGNALS
  45 
  46 #include "zend_signal.h"
  47 
  48 #ifdef ZTS
  49 ZEND_API int zend_signal_globals_id;
  50 #else
  51 zend_signal_globals_t zend_signal_globals;
  52 #endif
  53 
  54 static void zend_signal_handler(int signo, siginfo_t *siginfo, void *context TSRMLS_DC);
  55 static int zend_signal_register(int signo, void (*handler)(int, siginfo_t*, void*) TSRMLS_DC);
  56 
  57 #ifdef __CYGWIN__
  58 #define TIMEOUT_SIG SIGALRM
  59 #else
  60 #define TIMEOUT_SIG SIGPROF
  61 #endif
  62 
  63 static int zend_sigs[] = { TIMEOUT_SIG, SIGHUP, SIGINT, SIGQUIT, SIGTERM, SIGUSR1, SIGUSR2 };
  64 
  65 #define SA_FLAGS_MASK ~(SA_NODEFER | SA_RESETHAND)
  66 
  67 /* True globals, written only at process startup */
  68 static zend_signal_entry_t global_orig_handlers[NSIG];
  69 static sigset_t            global_sigmask;
  70 
  71 /* {{{ zend_signal_handler_defer
  72  *  Blocks signals if in critical section */
  73 void zend_signal_handler_defer(int signo, siginfo_t *siginfo, void *context)
  74 {
  75         int errno_save = errno;
  76         zend_signal_queue_t *queue, *qtmp;
  77         TSRMLS_FETCH();
  78 
  79         if (SIGG(active)) {
  80                 if (SIGG(depth) == 0) { /* try to handle signal */
  81                         if (SIGG(blocked) != -1) { /* inverse */
  82                                 SIGG(blocked) = -1; /* signal is not blocked */
  83                         }
  84                         if (SIGG(running) == 0) {
  85                                 SIGG(running) = 1;
  86                                 zend_signal_handler(signo, siginfo, context TSRMLS_CC);
  87 
  88                                 queue = SIGG(phead);
  89                                 SIGG(phead) = NULL;
  90 
  91                                 while (queue) {
  92                                         zend_signal_handler(queue->zend_signal.signo, queue->zend_signal.siginfo, queue->zend_signal.context TSRMLS_CC);
  93                                         qtmp = queue->next;
  94                                         queue->next = SIGG(pavail);
  95                                         queue->zend_signal.signo = 0;
  96                                         SIGG(pavail) = queue;
  97                                         queue = qtmp;
  98                                 }
  99                                 SIGG(running) = 0;
 100                         }
 101                 } else { /* delay signal handling */
 102                         SIGG(blocked) = 0; /* signal is blocked */
 103 
 104                         if ((queue = SIGG(pavail))) { /* if none available it's simply forgotton */
 105                                 SIGG(pavail) = queue->next;
 106                                 queue->zend_signal.signo = signo;
 107                                 queue->zend_signal.siginfo = siginfo;
 108                                 queue->zend_signal.context = context;
 109                                 queue->next = NULL;
 110 
 111                                 if (SIGG(phead) && SIGG(ptail)) {
 112                                         SIGG(ptail)->next = queue;
 113                                 } else {
 114                                         SIGG(phead) = queue;
 115                                 }
 116                                 SIGG(ptail) = queue;
 117                         }
 118 #if ZEND_DEBUG
 119                         else { /* this may not be safe to do, but could work and be useful */
 120                                 zend_output_debug_string(0, "zend_signal: not enough queue storage, lost signal (%d)", signo);
 121                         }
 122 #endif
 123                 }
 124         } else {
 125                 /* need to just run handler if we're inactive and getting a signal */
 126                 zend_signal_handler(signo, siginfo, context TSRMLS_CC);
 127         }
 128 
 129         errno = errno_save;
 130 } /* }}} */
 131 
 132 /* {{{ zend_signal_handler_unblock
 133  * Handle deferred signal from HANDLE_UNBLOCK_ALARMS */
 134 ZEND_API void zend_signal_handler_unblock(TSRMLS_D)
 135 {
 136         zend_signal_queue_t *queue;
 137         zend_signal_t zend_signal;
 138 
 139         if (SIGG(active)) {
 140                 SIGNAL_BEGIN_CRITICAL(); /* procmask to protect handler_defer as if it were called by the kernel */
 141                 queue = SIGG(phead);
 142                 SIGG(phead) = queue->next;
 143                 zend_signal = queue->zend_signal;
 144                 queue->next = SIGG(pavail);
 145                 queue->zend_signal.signo = 0;
 146                 SIGG(pavail) = queue;
 147 
 148                 zend_signal_handler_defer(zend_signal.signo, zend_signal.siginfo, zend_signal.context);
 149                 SIGNAL_END_CRITICAL();
 150         }
 151 }
 152 /* }}} */
 153 
 154 /* {{{ zend_signal_handler
 155  *  Call the previously registered handler for a signal
 156  */
 157 static void zend_signal_handler(int signo, siginfo_t *siginfo, void *context TSRMLS_DC)
 158 {
 159         int errno_save = errno;
 160         struct sigaction sa = {{0}};
 161         sigset_t sigset;
 162         zend_signal_entry_t p_sig = SIGG(handlers)[signo-1];
 163 
 164         if (p_sig.handler == SIG_DFL) { /* raise default handler */
 165                 if (sigaction(signo, NULL, &sa) == 0) {
 166                         sa.sa_handler = SIG_DFL;
 167                         sigemptyset(&sa.sa_mask);
 168 
 169                         sigemptyset(&sigset);
 170                         sigaddset(&sigset, signo);
 171 
 172                         if (sigaction(signo, &sa, NULL) == 0) {
 173                                 /* throw away any blocked signals */
 174                                 sigprocmask(SIG_UNBLOCK, &sigset, NULL);
 175                                 raise(signo);
 176                         }
 177                 }
 178         } else if (p_sig.handler != SIG_IGN) { /* ignore SIG_IGN */
 179                 if (p_sig.flags & SA_SIGINFO) {
 180                         if (p_sig.flags & SA_RESETHAND) {
 181                                 SIGG(handlers)[signo-1].flags   = 0;
 182                                 SIGG(handlers)[signo-1].handler = SIG_DFL;
 183                         }
 184                         (*(void (*)(int, siginfo_t*, void*))p_sig.handler)(signo, siginfo, context);
 185                 } else {
 186                         (*(void (*)(int))p_sig.handler)(signo);
 187                 }
 188         }
 189 
 190         errno = errno_save;
 191 } /* }}} */
 192 
 193 /* {{{ zend_sigaction
 194  *  Register a signal handler that will be deferred in critical sections */
 195 ZEND_API int zend_sigaction(int signo, const struct sigaction *act, struct sigaction *oldact TSRMLS_DC)
 196 {
 197         struct sigaction sa = {{0}};
 198         sigset_t sigset;
 199 
 200         if (oldact != NULL) {
 201                 oldact->sa_flags   = SIGG(handlers)[signo-1].flags;
 202                 oldact->sa_handler = (void *) SIGG(handlers)[signo-1].handler;
 203                 oldact->sa_mask    = global_sigmask;
 204         }
 205         if (act != NULL) {
 206                 SIGG(handlers)[signo-1].flags = act->sa_flags;
 207                 if (act->sa_flags & SA_SIGINFO) {
 208                         SIGG(handlers)[signo-1].handler = (void *) act->sa_sigaction;
 209                 } else {
 210                         SIGG(handlers)[signo-1].handler = (void *) act->sa_handler;
 211                 }
 212 
 213                 sa.sa_flags     = SA_SIGINFO | (act->sa_flags & SA_FLAGS_MASK);
 214                 sa.sa_sigaction = zend_signal_handler_defer;
 215                 sa.sa_mask      = global_sigmask;
 216 
 217                 if (sigaction(signo, &sa, NULL) < 0) {
 218                         zend_error(E_ERROR, "Error installing signal handler for %d", signo);
 219                 }
 220 
 221                 /* unsure this signal is not blocked */
 222                 sigemptyset(&sigset);
 223                 sigaddset(&sigset, signo);
 224                 zend_sigprocmask(SIG_UNBLOCK, &sigset, NULL);
 225         }
 226 
 227         return SUCCESS;
 228 }
 229 /* }}} */
 230 
 231 /* {{{ zend_signal
 232  *  Register a signal handler that will be deferred in critical sections */
 233 ZEND_API int zend_signal(int signo, void (*handler)(int) TSRMLS_DC)
 234 {
 235         struct sigaction sa = {{0}};
 236 
 237         sa.sa_flags   = 0;
 238         sa.sa_handler = handler;
 239         sa.sa_mask    = global_sigmask;
 240 
 241         return zend_sigaction(signo, &sa, NULL TSRMLS_CC);
 242 }
 243 /* }}} */
 244 
 245 /* {{{ zend_signal_register
 246  *  Set a handler for a signal we want to defer.
 247  *  Previously set handler must have been saved before.
 248  */
 249 static int zend_signal_register(int signo, void (*handler)(int, siginfo_t*, void*) TSRMLS_DC)
 250 {
 251         struct sigaction sa = {{0}};
 252 
 253         if (sigaction(signo, NULL, &sa) == 0) {
 254                 if ((sa.sa_flags & SA_SIGINFO) && sa.sa_sigaction == handler) {
 255                         return FAILURE;
 256                 }
 257 
 258                 SIGG(handlers)[signo-1].flags = sa.sa_flags;
 259                 if (sa.sa_flags & SA_SIGINFO) {
 260                         SIGG(handlers)[signo-1].handler = (void *)sa.sa_sigaction;
 261                 } else {
 262                         SIGG(handlers)[signo-1].handler = (void *)sa.sa_handler;
 263                 }
 264 
 265                 sa.sa_flags     = SA_SIGINFO; /* we'll use a siginfo handler */
 266                 sa.sa_sigaction = handler;
 267                 sa.sa_mask      = global_sigmask;
 268 
 269                 if (sigaction(signo, &sa, NULL) < 0) {
 270                         zend_error(E_ERROR, "Error installing signal handler for %d", signo);
 271                 }
 272 
 273                 return SUCCESS;
 274         }
 275         return FAILURE;
 276 } /* }}} */
 277 
 278 /* {{{ zend_signal_activate
 279  *  Install our signal handlers, per request */
 280 void zend_signal_activate(TSRMLS_D)
 281 {
 282         int x;
 283 
 284         memcpy(&SIGG(handlers), &global_orig_handlers, sizeof(global_orig_handlers));
 285 
 286         for (x=0; x < sizeof(zend_sigs) / sizeof(*zend_sigs); x++) {
 287                 zend_signal_register(zend_sigs[x], zend_signal_handler_defer TSRMLS_CC);
 288         }
 289 
 290         SIGG(active) = 1;
 291         SIGG(depth)  = 0;
 292 } /* }}} */
 293 
 294 /* {{{ zend_signal_deactivate
 295  * */
 296 void zend_signal_deactivate(TSRMLS_D)
 297 {
 298         int x;
 299         struct sigaction sa = {{0}};
 300 
 301         if (SIGG(check)) {
 302                 if (SIGG(depth) != 0) {
 303                         zend_error(E_CORE_WARNING, "zend_signal: shutdown with non-zero blocking depth (%d)", SIGG(depth));
 304                 }
 305                 /* did anyone steal our installed handler */
 306                 for (x=0; x < sizeof(zend_sigs) / sizeof(*zend_sigs); x++) {
 307                         sigaction(zend_sigs[x], NULL, &sa);
 308                         if (sa.sa_sigaction != zend_signal_handler_defer) {
 309                                 zend_error(E_CORE_WARNING, "zend_signal: handler was replaced for signal (%d) after startup", zend_sigs[x]);
 310                         }
 311                 }
 312         }
 313 
 314         SIGNAL_BEGIN_CRITICAL();
 315         SIGG(active) = 0;
 316         SIGG(running) = 0;
 317         SIGG(blocked) = -1;
 318         SIGG(depth) = 0;
 319         SIGNAL_END_CRITICAL();
 320 }
 321 /* }}} */
 322 
 323 static void zend_signal_globals_ctor(zend_signal_globals_t *zend_signal_globals TSRMLS_DC)
 324 {
 325         size_t x;
 326 
 327         memset(zend_signal_globals, 0, sizeof(*zend_signal_globals));
 328         zend_signal_globals->blocked = -1;
 329 
 330         for (x = 0; x < sizeof(zend_signal_globals->pstorage) / sizeof(*zend_signal_globals->pstorage); ++x) {
 331                 zend_signal_queue_t *queue = &zend_signal_globals->pstorage[x];
 332                 queue->zend_signal.signo = 0;
 333                 queue->next = zend_signal_globals->pavail;
 334                 zend_signal_globals->pavail = queue;
 335         }
 336 }
 337 
 338 static void zend_signal_globals_dtor(zend_signal_globals_t *zend_signal_globals TSRMLS_DC)
 339 {
 340         zend_signal_globals->blocked = -1;
 341 }
 342 
 343 /* {{{ zend_signal_startup
 344  * alloc zend signal globals */
 345 void zend_signal_startup()
 346 {
 347         int signo;
 348         struct sigaction sa = {{0}};
 349 
 350 #ifdef ZTS
 351         ts_allocate_id(&zend_signal_globals_id, sizeof(zend_signal_globals_t), (ts_allocate_ctor) zend_signal_globals_ctor, (ts_allocate_dtor) zend_signal_globals_dtor);
 352 #else
 353         zend_signal_globals_ctor(&zend_signal_globals);
 354 #endif
 355 
 356         /* Used to block signals during execution of signal handlers */
 357         sigfillset(&global_sigmask);
 358         sigdelset(&global_sigmask, SIGILL);
 359         sigdelset(&global_sigmask, SIGABRT);
 360         sigdelset(&global_sigmask, SIGFPE);
 361         sigdelset(&global_sigmask, SIGKILL);
 362         sigdelset(&global_sigmask, SIGSEGV);
 363         sigdelset(&global_sigmask, SIGCONT);
 364         sigdelset(&global_sigmask, SIGSTOP);
 365         sigdelset(&global_sigmask, SIGTSTP);
 366         sigdelset(&global_sigmask, SIGTTIN);
 367         sigdelset(&global_sigmask, SIGTTOU);
 368 #ifdef SIGBUS
 369         sigdelset(&global_sigmask, SIGBUS);
 370 #endif
 371 #ifdef SIGSYS
 372         sigdelset(&global_sigmask, SIGSYS);
 373 #endif
 374 #ifdef SIGTRAP
 375         sigdelset(&global_sigmask, SIGTRAP);
 376 #endif
 377 
 378         /* Save previously registered signal handlers into orig_handlers */
 379         memset(&global_orig_handlers, 0, sizeof(global_orig_handlers));
 380         for (signo = 1; signo < NSIG; ++signo) {
 381                 if (sigaction(signo, NULL, &sa) == 0) {
 382                         global_orig_handlers[signo-1].flags = sa.sa_flags;
 383                         if (sa.sa_flags & SA_SIGINFO) {
 384                                 global_orig_handlers[signo-1].handler = (void *) sa.sa_sigaction;
 385                         } else {
 386                                 global_orig_handlers[signo-1].handler = (void *) sa.sa_handler;
 387                         }
 388                 }
 389         }
 390 }
 391 /* }}} */
 392 
 393 /* {{{ zend_signal_shutdown
 394  * called by zend_shutdown */
 395 void zend_signal_shutdown(TSRMLS_D)
 396 {
 397 #ifndef ZTS
 398         zend_signal_globals_dtor(&zend_signal_globals);
 399 #endif
 400 }
 401 /* }}} */
 402 
 403 
 404 #endif /* ZEND_SIGNALS */
 405 
 406 /*
 407  * Local variables:
 408  * tab-width: 4
 409  * c-basic-offset: 4
 410  * indent-tabs-mode: t
 411  * End:
 412  * vim600: fdm=marker
 413  * vim: noet sw=4 ts=4
 414  */

/* [<][>][^][v][top][bottom][index][help] */