Busybox: Upgrade to 1.21.1 (stable). lsof active.
[tomato.git] / release / src / router / php / Zend / zend_signal.c
blobf61ae0b176cd00a69c7c023161eab286c9e9aed0
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 +----------------------------------------------------------------------+
19 This software was contributed to PHP by Facebook Inc. in 2008.
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.
25 All other licensing and usage conditions are those of the PHP Group.
28 /* $Id$ */
30 #define _GNU_SOURCE
31 #include <string.h>
33 #include "zend.h"
34 #include "zend_globals.h"
36 #ifdef HAVE_SIGNAL_H
37 #include <signal.h>
38 #endif
40 #ifdef HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif
44 #ifdef ZEND_SIGNALS
46 #include "zend_signal.h"
48 #ifdef ZTS
49 ZEND_API int zend_signal_globals_id;
50 #else
51 zend_signal_globals_t zend_signal_globals;
52 #endif
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);
57 #ifdef __CYGWIN__
58 #define TIMEOUT_SIG SIGALRM
59 #else
60 #define TIMEOUT_SIG SIGPROF
61 #endif
63 static int zend_sigs[] = { TIMEOUT_SIG, SIGHUP, SIGINT, SIGQUIT, SIGTERM, SIGUSR1, SIGUSR2 };
65 #define SA_FLAGS_MASK ~(SA_NODEFER | SA_RESETHAND)
67 /* True globals, written only at process startup */
68 static zend_signal_entry_t global_orig_handlers[NSIG];
69 static sigset_t global_sigmask;
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)
75 int errno_save = errno;
76 zend_signal_queue_t *queue, *qtmp;
77 TSRMLS_FETCH();
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 */
84 if (SIGG(running) == 0) {
85 SIGG(running) = 1;
86 zend_signal_handler(signo, siginfo, context TSRMLS_CC);
88 queue = SIGG(phead);
89 SIGG(phead) = NULL;
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;
99 SIGG(running) = 0;
101 } else { /* delay signal handling */
102 SIGG(blocked) = 0; /* signal is blocked */
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;
111 if (SIGG(phead) && SIGG(ptail)) {
112 SIGG(ptail)->next = queue;
113 } else {
114 SIGG(phead) = queue;
116 SIGG(ptail) = queue;
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);
122 #endif
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);
129 errno = errno_save;
130 } /* }}} */
132 /* {{{ zend_signal_handler_unblock
133 * Handle deferred signal from HANDLE_UNBLOCK_ALARMS */
134 ZEND_API void zend_signal_handler_unblock(TSRMLS_D)
136 zend_signal_queue_t *queue;
137 zend_signal_t zend_signal;
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;
148 zend_signal_handler_defer(zend_signal.signo, zend_signal.siginfo, zend_signal.context);
149 SIGNAL_END_CRITICAL();
152 /* }}} */
154 /* {{{ zend_signal_handler
155 * Call the previously registered handler for a signal
157 static void zend_signal_handler(int signo, siginfo_t *siginfo, void *context TSRMLS_DC)
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];
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);
169 sigemptyset(&sigset);
170 sigaddset(&sigset, signo);
172 if (sigaction(signo, &sa, NULL) == 0) {
173 /* throw away any blocked signals */
174 sigprocmask(SIG_UNBLOCK, &sigset, NULL);
175 raise(signo);
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;
184 (*(void (*)(int, siginfo_t*, void*))p_sig.handler)(signo, siginfo, context);
185 } else {
186 (*(void (*)(int))p_sig.handler)(signo);
190 errno = errno_save;
191 } /* }}} */
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)
197 struct sigaction sa = {{0}};
198 sigset_t sigset;
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;
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;
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;
217 if (sigaction(signo, &sa, NULL) < 0) {
218 zend_error(E_WARNING, "Error installing signal handler for %d", signo);
221 /* unsure this signal is not blocked */
222 sigemptyset(&sigset);
223 sigaddset(&sigset, signo);
224 zend_sigprocmask(SIG_UNBLOCK, &sigset, NULL);
227 return SUCCESS;
229 /* }}} */
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)
235 struct sigaction sa = {{0}};
237 sa.sa_flags = 0;
238 sa.sa_handler = handler;
239 sa.sa_mask = global_sigmask;
241 return zend_sigaction(signo, &sa, NULL TSRMLS_CC);
243 /* }}} */
245 /* {{{ zend_signal_register
246 * Set a handler for a signal we want to defer.
247 * Previously set handler must have been saved before.
249 static int zend_signal_register(int signo, void (*handler)(int, siginfo_t*, void*) TSRMLS_DC)
251 struct sigaction sa = {{0}};
253 if (sigaction(signo, NULL, &sa) == 0) {
254 if ((sa.sa_flags & SA_SIGINFO) && sa.sa_sigaction == handler) {
255 return FAILURE;
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;
265 sa.sa_flags = SA_SIGINFO; /* we'll use a siginfo handler */
266 sa.sa_sigaction = handler;
267 sa.sa_mask = global_sigmask;
269 if (sigaction(signo, &sa, NULL) < 0) {
270 zend_error(E_WARNING, "Error installing signal handler for %d", signo);
273 return SUCCESS;
275 return FAILURE;
276 } /* }}} */
278 /* {{{ zend_signal_activate
279 * Install our signal handlers, per request */
280 void zend_signal_activate(TSRMLS_D)
282 int x;
284 memcpy(&SIGG(handlers), &global_orig_handlers, sizeof(global_orig_handlers));
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);
290 SIGG(active) = 1;
291 SIGG(depth) = 0;
292 } /* }}} */
294 /* {{{ zend_signal_deactivate
295 * */
296 void zend_signal_deactivate(TSRMLS_D)
298 int x;
299 struct sigaction sa = {{0}};
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));
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]);
314 SIGNAL_BEGIN_CRITICAL();
315 SIGG(active) = 0;
316 SIGG(running) = 0;
317 SIGG(blocked) = -1;
318 SIGG(depth) = 0;
319 SIGNAL_END_CRITICAL();
321 /* }}} */
323 static void zend_signal_globals_ctor(zend_signal_globals_t *zend_signal_globals TSRMLS_DC)
325 size_t x;
327 memset(zend_signal_globals, 0, sizeof(*zend_signal_globals));
328 zend_signal_globals->blocked = -1;
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;
338 static void zend_signal_globals_dtor(zend_signal_globals_t *zend_signal_globals TSRMLS_DC)
340 zend_signal_globals->blocked = -1;
343 /* {{{ zend_signal_startup
344 * alloc zend signal globals */
345 void zend_signal_startup()
347 int signo;
348 struct sigaction sa = {{0}};
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
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
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;
391 /* }}} */
393 /* {{{ zend_signal_shutdown
394 * called by zend_shutdown */
395 void zend_signal_shutdown(TSRMLS_D)
397 #ifndef ZTS
398 zend_signal_globals_dtor(&zend_signal_globals);
399 #endif
401 /* }}} */
404 #endif /* ZEND_SIGNALS */
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