Annotation of embedaddon/php/Zend/zend_signal.c, revision 1.1
1.1 ! misho 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_WARNING, "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_WARNING, "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: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>