/* {{{ zend_signal_register * Set a handler for a signal we want to defer. * Previously set handler must have been saved before. */ static int zend_signal_register(int signo, void (*handler)(int, siginfo_t*, void*)) { struct sigaction sa = {{0}}; if (sigaction(signo, NULL, &sa) == 0) { if ((sa.sa_flags & SA_SIGINFO) && sa.sa_sigaction == handler) { return FAILURE; } SIGG(handlers)[signo-1].flags = sa.sa_flags; if (sa.sa_flags & SA_SIGINFO) { SIGG(handlers)[signo-1].handler = (void *)sa.sa_sigaction; } else { SIGG(handlers)[signo-1].handler = (void *)sa.sa_handler; } sa.sa_flags = SA_SIGINFO; /* we'll use a siginfo handler */ sa.sa_sigaction = handler; sa.sa_mask = global_sigmask; if (sigaction(signo, &sa, NULL) < 0) { zend_error_noreturn(E_ERROR, "Error installing signal handler for %d", signo); } return SUCCESS; } return FAILURE; } /* }}} */
/* {{{ zend_sigaction * Register a signal handler that will be deferred in critical sections */ ZEND_API int zend_sigaction(int signo, const struct sigaction *act, struct sigaction *oldact) { struct sigaction sa = {{0}}; sigset_t sigset; if (oldact != NULL) { oldact->sa_flags = SIGG(handlers)[signo-1].flags; oldact->sa_handler = (void *) SIGG(handlers)[signo-1].handler; oldact->sa_mask = global_sigmask; } if (act != NULL) { SIGG(handlers)[signo-1].flags = act->sa_flags; if (act->sa_flags & SA_SIGINFO) { SIGG(handlers)[signo-1].handler = (void *) act->sa_sigaction; } else { SIGG(handlers)[signo-1].handler = (void *) act->sa_handler; } sa.sa_flags = SA_SIGINFO | (act->sa_flags & SA_FLAGS_MASK); sa.sa_sigaction = zend_signal_handler_defer; sa.sa_mask = global_sigmask; if (sigaction(signo, &sa, NULL) < 0) { zend_error_noreturn(E_ERROR, "Error installing signal handler for %d", signo); } /* unsure this signal is not blocked */ sigemptyset(&sigset); sigaddset(&sigset, signo); zend_sigprocmask(SIG_UNBLOCK, &sigset, NULL); } return SUCCESS; }
/* {{{ zend_signal_handler * Call the previously registered handler for a signal */ static void zend_signal_handler(int signo, siginfo_t *siginfo, void *context) { int errno_save = errno; struct sigaction sa = {{0}}; sigset_t sigset; zend_signal_entry_t p_sig = SIGG(handlers)[signo-1]; if (p_sig.handler == SIG_DFL) { /* raise default handler */ if (sigaction(signo, NULL, &sa) == 0) { sa.sa_handler = SIG_DFL; sigemptyset(&sa.sa_mask); sigemptyset(&sigset); sigaddset(&sigset, signo); if (sigaction(signo, &sa, NULL) == 0) { /* throw away any blocked signals */ sigprocmask(SIG_UNBLOCK, &sigset, NULL); raise(signo); } } } else if (p_sig.handler != SIG_IGN) { /* ignore SIG_IGN */ if (p_sig.flags & SA_SIGINFO) { if (p_sig.flags & SA_RESETHAND) { SIGG(handlers)[signo-1].flags = 0; SIGG(handlers)[signo-1].handler = SIG_DFL; } (*(void (*)(int, siginfo_t*, void*))p_sig.handler)(signo, siginfo, context); } else { (*(void (*)(int))p_sig.handler)(signo); } } errno = errno_save; } /* }}} */
/* {{{ zend_signal_activate * Install our signal handlers, per request */ void zend_signal_activate(void) { int x; memcpy(&SIGG(handlers), &global_orig_handlers, sizeof(global_orig_handlers)); for (x = 0; x < sizeof(zend_sigs) / sizeof(*zend_sigs); x++) { zend_signal_register(zend_sigs[x], zend_signal_handler_defer); } SIGG(active) = 1; SIGG(depth) = 0; } /* }}} */
/* {{{ zend_signal_handler_unblock * Handle deferred signal from HANDLE_UNBLOCK_ALARMS */ ZEND_API void zend_signal_handler_unblock(TSRMLS_D) { zend_signal_queue_t *queue; zend_signal_t zend_signal; if (SIGG(active)) { SIGNAL_BEGIN_CRITICAL(); /* procmask to protect handler_defer as if it were called by the kernel */ queue = SIGG(phead); SIGG(phead) = queue->next; zend_signal = queue->zend_signal; queue->next = SIGG(pavail); queue->zend_signal.signo = 0; SIGG(pavail) = queue; zend_signal_handler_defer(zend_signal.signo, zend_signal.siginfo, zend_signal.context); SIGNAL_END_CRITICAL(); } }
/* {{{ zend_signal_handler * Call the previously registered handler for a signal */ static void zend_signal_handler(int signo, siginfo_t *siginfo, void *context) { int errno_save = errno; struct sigaction sa; sigset_t sigset; zend_signal_entry_t p_sig = SIGG(handlers)[signo-1]; if (p_sig.handler == SIG_DFL) { /* raise default handler */ if (sigaction(signo, NULL, &sa) == 0) { sa.sa_handler = SIG_DFL; sigemptyset(&sa.sa_mask); sigemptyset(&sigset); sigaddset(&sigset, signo); if (sigaction(signo, &sa, NULL) == 0) { /* throw away any blocked signals */ zend_sigprocmask(SIG_UNBLOCK, &sigset, NULL); #ifdef ZTS # define RAISE_ERROR "raise() failed\n" if (raise(signo) != 0) { /* On some systems raise() fails with errno 3: No such process */ kill(getpid(), signo); } #else kill(getpid(), signo); #endif } } } else { if (p_sig.flags & SA_SIGINFO) { if (p_sig.flags & SA_RESETHAND) { SIGG(handlers)[signo-1].flags = 0; SIGG(handlers)[signo-1].handler = SIG_DFL; } (*(void (*)(int, siginfo_t*, void*))p_sig.handler)(signo, siginfo, context); } else { (*(void (*)(int))p_sig.handler)(signo); } } errno = errno_save; } /* }}} */
/* {{{ zend_signal_deactivate * */ void zend_signal_deactivate(void) { if (SIGG(check)) { int x; struct sigaction sa = {{0}}; if (SIGG(depth) != 0) { zend_error(E_CORE_WARNING, "zend_signal: shutdown with non-zero blocking depth (%d)", SIGG(depth)); } /* did anyone steal our installed handler */ for (x = 0; x < sizeof(zend_sigs) / sizeof(*zend_sigs); x++) { sigaction(zend_sigs[x], NULL, &sa); if (sa.sa_sigaction != zend_signal_handler_defer) { zend_error(E_CORE_WARNING, "zend_signal: handler was replaced for signal (%d) after startup", zend_sigs[x]); } } } SIGNAL_BEGIN_CRITICAL(); SIGG(active) = 0; SIGG(running) = 0; SIGG(blocked) = 0; SIGG(depth) = 0; SIGNAL_END_CRITICAL(); }
/* {{{ zend_signal_handler_defer * Blocks signals if in critical section */ void zend_signal_handler_defer(int signo, siginfo_t *siginfo, void *context) { int errno_save = errno; zend_signal_queue_t *queue, *qtmp; TSRMLS_FETCH(); if (SIGG(active)) { if (SIGG(depth) == 0) { /* try to handle signal */ if (SIGG(blocked) != -1) { /* inverse */ SIGG(blocked) = -1; /* signal is not blocked */ } if (SIGG(running) == 0) { SIGG(running) = 1; zend_signal_handler(signo, siginfo, context TSRMLS_CC); queue = SIGG(phead); SIGG(phead) = NULL; while (queue) { zend_signal_handler(queue->zend_signal.signo, queue->zend_signal.siginfo, queue->zend_signal.context TSRMLS_CC); qtmp = queue->next; queue->next = SIGG(pavail); queue->zend_signal.signo = 0; SIGG(pavail) = queue; queue = qtmp; } SIGG(running) = 0; } } else { /* delay signal handling */ SIGG(blocked) = 0; /* signal is blocked */ if ((queue = SIGG(pavail))) { /* if none available it's simply forgotton */ SIGG(pavail) = queue->next; queue->zend_signal.signo = signo; queue->zend_signal.siginfo = siginfo; queue->zend_signal.context = context; queue->next = NULL; if (SIGG(phead) && SIGG(ptail)) { SIGG(ptail)->next = queue; } else { SIGG(phead) = queue; } SIGG(ptail) = queue; } #if ZEND_DEBUG else { /* this may not be safe to do, but could work and be useful */ zend_output_debug_string(0, "zend_signal: not enough queue storage, lost signal (%d)", signo); } #endif } } else { /* need to just run handler if we're inactive and getting a signal */ zend_signal_handler(signo, siginfo, context TSRMLS_CC); } errno = errno_save; } /* }}} */
zend_signal_handler_defer(zend_signal.signo, zend_signal.siginfo, zend_signal.context); SIGNAL_END_CRITICAL(); } } /* }}} */ /* {{{ zend_signal_handler * Call the previously registered handler for a signal */ static void zend_signal_handler(int signo, siginfo_t *siginfo, void *context TSRMLS_DC) { int errno_save = errno; struct sigaction sa = {{0}}; sigset_t sigset; zend_signal_entry_t p_sig = SIGG(handlers)[signo-1]; if (p_sig.handler == SIG_DFL) { /* raise default handler */ if (sigaction(signo, NULL, &sa) == 0) { sa.sa_handler = SIG_DFL; sigemptyset(&sa.sa_mask); sigemptyset(&sigset); sigaddset(&sigset, signo); if (sigaction(signo, &sa, NULL) == 0) { /* throw away any blocked signals */ sigprocmask(SIG_UNBLOCK, &sigset, NULL); raise(signo); } }