Annotation of embedaddon/php/Zend/zend_signal.c, revision 1.1.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>