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>