New PHP5 APC - version 3.0.19, using PHP5 5.2.0-8+etch11,
[php5-apc.git] / apc_signal.c
1 /*
2   +----------------------------------------------------------------------+
3   | APC                                                                  |
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   +----------------------------------------------------------------------+
17
18    This software was contributed to PHP by Facebook Inc. in 2007.
19    
20    Future revisions and derivatives of this source code must acknowledge
21    Facebook Inc. as the original contributor of this module by leaving
22    this note intact in the source code.
23
24    All other licensing and usage conditions are those of the PHP Group.
25  */
26
27  /* $Id: apc_signal.c,v 1.2.2.3 2008/05/11 18:57:00 rasmus Exp $ */
28
29  /* Allows apc to install signal handlers and maintain signalling
30     to already registered handlers. Registers all signals that
31     coredump by default and unmaps the shared memory segment
32     before the coredump. Note: PHP module init is called before 
33     signals are set by Apache and thus apc_set_signals should
34     be called in request init (RINIT)
35   */
36
37 #include <signal.h>
38 #include "apc_globals.h"
39 #include "apc_sma.h"
40 #include "apc_signal.h"
41
42 static apc_signal_info_t apc_signal_info = {0};
43
44 static int apc_register_signal(int signo, void (*handler)(int, siginfo_t*, void*));
45 static void apc_rehandle_signal(int signo, siginfo_t *siginfo, void *context);
46 static void apc_core_unmap(int signo, siginfo_t *siginfo, void *context);
47
48 /* {{{ apc_core_unmap 
49  *  Coredump signal handler, unmaps shm and calls previously installed handlers 
50  */
51 static void apc_core_unmap(int signo, siginfo_t *siginfo, void *context) 
52 {
53     apc_sma_cleanup();
54     apc_rehandle_signal(signo, siginfo, context);
55
56 #if !defined(WIN32) && !defined(NETWARE)
57     kill(getpid(), signo);
58 #else
59     raise(signo);
60 #endif
61 } /* }}} */
62
63 /* {{{ apc_rehandle_signal
64  *  Call the previously registered handler for a signal
65  */
66 static void apc_rehandle_signal(int signo, siginfo_t *siginfo, void *context)
67 {
68     int i;
69     apc_signal_entry_t p_sig = {0};
70
71     for (i=0;  (i < apc_signal_info.installed && p_sig.signo != signo);  i++) {
72         p_sig = *apc_signal_info.prev[i];
73         if (p_sig.signo == signo) {
74             if (p_sig.siginfo) {
75                 (*(void (*)(int, siginfo_t*, void*))p_sig.handler)(signo, siginfo, context);
76             } else {
77                 (*(void (*)(int))p_sig.handler)(signo);
78             }
79         }
80     }
81
82 } /* }}} */
83
84 /* {{{ apc_register_signal
85  *  Set a handler for a previously installed signal and save so we can 
86  *  callback when handled 
87  */
88 static int apc_register_signal(int signo, void (*handler)(int, siginfo_t*, void*))
89 {
90 #if HAVE_SIGACTION
91     struct sigaction sa = {{0}};
92     apc_signal_entry_t p_sig = {0};
93
94     if (sigaction(signo, NULL, &sa) == 0) {
95         if ((void*)sa.sa_handler == (void*)handler) {
96             return SUCCESS;
97         }
98
99         if (sa.sa_handler != SIG_ERR && sa.sa_handler != SIG_DFL && sa.sa_handler != SIG_IGN) {
100             p_sig.signo = signo;
101             p_sig.siginfo = ((sa.sa_flags & SA_SIGINFO) == SA_SIGINFO);
102             p_sig.handler = (void *)sa.sa_handler;
103            
104             apc_signal_info.prev = (apc_signal_entry_t **)apc_erealloc(apc_signal_info.prev, (apc_signal_info.installed+1)*sizeof(apc_signal_entry_t *));
105             apc_signal_info.prev[apc_signal_info.installed] = (apc_signal_entry_t *)apc_emalloc(sizeof(apc_signal_entry_t));
106             *apc_signal_info.prev[apc_signal_info.installed++] = p_sig;
107         } else {
108             /* inherit flags and mask if already set */
109             sigemptyset(&sa.sa_mask);
110             sa.sa_flags = 0;
111             sa.sa_flags |= SA_SIGINFO; /* we'll use a siginfo handler */
112 #if defined(SA_ONESHOT)
113             sa.sa_flags = SA_ONESHOT;
114 #elif defined(SA_RESETHAND)
115             sa.sa_flags = SA_RESETHAND;
116 #endif
117         }
118         sa.sa_handler = (void*)handler;
119
120         if (sigaction(signo, &sa, NULL) < 0) {
121             apc_wprint("Error installing apc signal handler for %d", signo);
122         }
123
124         return SUCCESS;
125     }
126 #endif
127     return FAILURE;
128 } /* }}} */
129
130 /* {{{ apc_set_signals
131  *  Install our signal handlers */
132 void apc_set_signals(TSRMLS_D) 
133 {
134     if (APCG(coredump_unmap) && apc_signal_info.installed == 0) {
135         /* ISO C standard signals that coredump */
136         apc_register_signal(SIGSEGV, apc_core_unmap);
137         apc_register_signal(SIGABRT, apc_core_unmap);
138         apc_register_signal(SIGFPE, apc_core_unmap);
139         apc_register_signal(SIGILL, apc_core_unmap);
140         /* extended signals that coredump */
141 #ifdef SIGBUS
142         apc_register_signal(SIGBUS, apc_core_unmap);
143 #endif
144 #ifdef SIGABORT
145         apc_register_signal(SIGABORT, apc_core_unmap);
146 #endif
147 #ifdef SIGEMT
148         apc_register_signal(SIGEMT, apc_core_unmap);
149 #endif
150 #ifdef SIGIOT
151         apc_register_signal(SIGIOT, apc_core_unmap);
152 #endif
153 #ifdef SIGQUIT
154         apc_register_signal(SIGQUIT, apc_core_unmap);
155 #endif
156 #ifdef SIGSYS
157         apc_register_signal(SIGSYS, apc_core_unmap);
158 #endif
159 #ifdef SIGTRAP
160         apc_register_signal(SIGTRAP, apc_core_unmap);
161 #endif
162 #ifdef SIGXCPU
163         apc_register_signal(SIGXCPU, apc_core_unmap);
164 #endif
165 #ifdef SIGXFSZ
166         apc_register_signal(SIGXFSZ, apc_core_unmap);
167 #endif
168     }
169 } /* }}} */
170
171 /* {{{ apc_set_signals
172  *  cleanup signals for shutdown */
173 void apc_shutdown_signals() 
174 {
175     int i=0;
176     if (apc_signal_info.installed > 0) {
177         for (i=0;  (i < apc_signal_info.installed);  i++) {
178             apc_efree(apc_signal_info.prev[i]);
179         }
180         apc_efree(apc_signal_info.prev);
181         apc_signal_info.installed = 0; /* just in case */
182     }
183 }
184
185 /*
186  * Local variables:
187  * tab-width: 4
188  * c-basic-offset: 4
189  * End:
190  * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
191  * vim<600: expandtab sw=4 ts=4 sts=4
192  */