File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / Zend / zend_signal.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:34:36 2012 UTC (12 years, 1 month ago) by misho
Branches: php, MAIN
CVS tags: v5_4_3elwix, v5_4_29p0, v5_4_29, v5_4_20p0, v5_4_20, v5_4_17p0, v5_4_17, HEAD
php 5.4.3+patches

    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: zend_signal.c,v 1.1.1.1 2012/05/29 12:34:36 misho Exp $ */
   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>