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>