comparison libfreeDiameter/signal.c @ 235:8773740401a5

Centralized signal handlers management in the library
author Sebastien Decugis <sdecugis@nict.go.jp>
date Fri, 05 Mar 2010 19:01:48 +0900
parents
children 60f34df3e025
comparison
equal deleted inserted replaced
234:f91fe0b85928 235:8773740401a5
1 /*********************************************************************************************************
2 * Software License Agreement (BSD License) *
3 * Author: Sebastien Decugis <sdecugis@nict.go.jp> *
4 * *
5 * Copyright (c) 2009, WIDE Project and NICT *
6 * All rights reserved. *
7 * *
8 * Redistribution and use of this software in source and binary forms, with or without modification, are *
9 * permitted provided that the following conditions are met: *
10 * *
11 * * Redistributions of source code must retain the above *
12 * copyright notice, this list of conditions and the *
13 * following disclaimer. *
14 * *
15 * * Redistributions in binary form must reproduce the above *
16 * copyright notice, this list of conditions and the *
17 * following disclaimer in the documentation and/or other *
18 * materials provided with the distribution. *
19 * *
20 * * Neither the name of the WIDE Project or NICT nor the *
21 * names of its contributors may be used to endorse or *
22 * promote products derived from this software without *
23 * specific prior written permission of WIDE Project and *
24 * NICT. *
25 * *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
27 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
28 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
29 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
32 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
33 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
34 *********************************************************************************************************/
35
36 #include "libfD.h"
37
38 #include <signal.h>
39
40 /* List of signal names */
41 #ifdef HAVE_SIGNALENT_H
42 const char *const fd_sig_str[] = {
43 # include "signalent.h"
44 };
45 const int fd_sig_nstr = sizeof fd_sig_str / sizeof fd_sig_str[0];
46 #endif /* HAVE_SIGNALENT_H */
47
48 /* A structure to hold the registered signal handlers */
49 struct sig_hdl {
50 struct fd_list chain; /* Link in the sig_hdl_list ordered by signal */
51 int signal; /* The signal this handler is registered for */
52 void (*sig_hdl)(int);/* The callback to call when the signal is caught */
53 pthread_t sig_thr; /* The thread that receives the signal */
54 char *modname; /* The name of the module who registered the signal (for debug) */
55 };
56
57 /* The list of sig_hdl, and the mutex to protect it */
58 static struct fd_list sig_hdl_list = FD_LIST_INITIALIZER(sig_hdl_list);
59 static pthread_mutex_t sig_hdl_lock = PTHREAD_MUTEX_INITIALIZER;
60
61 /* Detached thread attribute */
62 static pthread_attr_t detached;
63
64 /* Note if the module was initialized */
65 static int sig_initialized = 0;
66
67 /* Initialize the support for signals */
68 int fd_sig_init(void)
69 {
70 sigset_t sig_all;
71
72 TRACE_ENTRY("");
73
74 if (sig_initialized)
75 return 0;
76
77 /* Block all signals from the current thread and all its future children, so that signals are delivered only to our sig_hdl->sig_thr */
78 sigfillset(&sig_all);
79 CHECK_POSIX( pthread_sigmask(SIG_BLOCK, &sig_all, NULL) );
80
81 /* Initialize the detached attribute */
82 CHECK_POSIX( pthread_attr_init(&detached) );
83 CHECK_POSIX( pthread_attr_setdetachstate(&detached, PTHREAD_CREATE_DETACHED) );
84
85 sig_initialized++;
86
87 /* That's all we have to do here ... */
88 return 0;
89 }
90
91
92 /* This thread (created detached) does call the signal handler */
93 static void * signal_caller(void * arg)
94 {
95 struct sig_hdl * me = arg;
96 char buf[40];
97
98 /* Name this thread */
99 snprintf(buf, sizeof(buf), "cb %d:%s:%s", me->signal, SIGNALSTR(me->signal), me->modname);
100 fd_log_threadname ( buf );
101
102 TRACE_ENTRY("%p", me);
103
104 /* Call the signal handler */
105 (*me->sig_hdl)(me->signal);
106
107 TRACE_DEBUG(CALL, "Callback completed");
108
109 /* Done! */
110 return NULL;
111 }
112
113 /* This thread "really" receives the signal and starts the signal_caller thread */
114 static void * signal_catcher(void * arg)
115 {
116 struct sig_hdl * me = arg;
117 sigset_t ss;
118 char buf[40];
119
120 ASSERT(arg);
121
122 /* Name this thread */
123 snprintf(buf, sizeof(buf), "catch %d:%s:%s", me->signal, SIGNALSTR(me->signal), me->modname);
124 fd_log_threadname ( buf );
125
126 TRACE_ENTRY("%p", me);
127
128 sigemptyset(&ss);
129 sigaddset(&ss, me->signal);
130
131 /* Now loop on the reception of the signal */
132 while (1) {
133 int sig;
134 pthread_t th;
135
136 /* Wait to receive the next signal */
137 CHECK_POSIX_DO( sigwait(&ss, &sig), break );
138
139 TRACE_DEBUG(FULL, "Signal %d caught", sig);
140
141 /* Create the thread that will call the handler */
142 CHECK_POSIX_DO( pthread_create( &th, &detached, signal_caller, arg ), break );
143 }
144
145 /* An error occurred... What should we do ? */
146 TRACE_DEBUG(INFO, "!!! ERROR !!! The signal catcher for %d:%s:%s is terminating!", me->signal, SIGNALSTR(me->signal), me->modname);
147
148 /* Better way to handle this ? */
149 ASSERT(0);
150 return NULL;
151 }
152
153 /* Register a new callback to be called on reception of a given signal (it receives the signal as parameter) */
154 /* EALREADY will be returned if there is already a callback registered on this signal */
155 /* NOTE: the signal handler will be called from a new detached thread */
156 int fd_sig_register(int signal, char * modname, void (*handler)(int signal))
157 {
158 struct sig_hdl * new;
159 struct fd_list * next = NULL;
160 int matched = 0;
161
162 TRACE_ENTRY("%d %p %p", signal, modname, handler);
163 CHECK_PARAMS( signal && modname && handler && sig_initialized );
164
165 /* Alloc all memory before taking the lock */
166 CHECK_MALLOC( new = malloc(sizeof(struct sig_hdl)) );
167 memset(new, 0, sizeof(struct sig_hdl));
168 fd_list_init(&new->chain, new);
169 new->signal = signal;
170 new->sig_hdl = handler;
171 CHECK_MALLOC_DO( new->modname = strdup(modname), { free(new); return ENOMEM; } );
172
173 /* Search in the list if we already have a handler for this signal */
174 CHECK_POSIX(pthread_mutex_lock(&sig_hdl_lock));
175 for (next = sig_hdl_list.next; next != &sig_hdl_list; next = next->next) {
176 struct sig_hdl * nh = (struct sig_hdl *)next;
177
178 if (nh->signal < signal)
179 continue;
180 if (nh->signal == signal) {
181 matched = 1;
182 TRACE_DEBUG(INFO, "Signal %d (%s) is already registered by module '%s'", signal, SIGNALSTR(signal), nh->modname);
183 }
184 break;
185 }
186 if (!matched)
187 /* Insert the new element before the next handle */
188 fd_list_insert_before(next, &new->chain);
189
190 CHECK_POSIX(pthread_mutex_unlock(&sig_hdl_lock));
191
192 if (matched)
193 return EALREADY; /* Already registered... */
194
195 /* OK, now start the thread */
196 CHECK_POSIX( pthread_create( &new->sig_thr, NULL, signal_catcher, new ) );
197
198 /* All good */
199 return 0;
200 }
201
202 /* Dump list of handlers */
203 void fd_sig_dump(int level, int indent)
204 {
205 struct fd_list * li = NULL;
206
207 if (!TRACE_BOOL(level))
208 return;
209
210
211 CHECK_POSIX_DO(pthread_mutex_lock(&sig_hdl_lock), /* continue */);
212 if (!FD_IS_LIST_EMPTY(&sig_hdl_list))
213 fd_log_debug("%*sList of registered signal handlers:\n", indent, "");
214
215 for (li = sig_hdl_list.next; li != &sig_hdl_list; li = li->next) {
216 struct sig_hdl * h = (struct sig_hdl *)li;
217
218 fd_log_debug("%*s - sig %*d (%s) => %p in module %s\n", indent, "", 2, h->signal, SIGNALSTR(h->signal), h->sig_hdl, h->modname);
219 }
220 CHECK_POSIX_DO(pthread_mutex_unlock(&sig_hdl_lock), /* continue */);
221
222 return;
223 }
224
225
226 /* Remove a callback */
227 int fd_sig_unregister(int signal)
228 {
229 struct fd_list * li = NULL;
230 struct sig_hdl * h = NULL;
231
232 TRACE_ENTRY("%d", signal);
233 CHECK_PARAMS( signal && sig_initialized );
234
235 /* Search in the list if we already have a handler for this signal */
236 CHECK_POSIX(pthread_mutex_lock(&sig_hdl_lock));
237 for (li = sig_hdl_list.next; li != &sig_hdl_list; li = li->next) {
238 struct sig_hdl * nh = (struct sig_hdl *)li;
239
240 if (nh->signal < signal)
241 continue;
242 if (nh->signal == signal) {
243 h = nh;
244 fd_list_unlink(&h->chain);
245 }
246 break;
247 }
248 CHECK_POSIX(pthread_mutex_unlock(&sig_hdl_lock));
249
250 if (!h)
251 return ENOENT;
252
253 /* Stop the catcher thread */
254 CHECK_FCT( fd_thr_term(&h->sig_thr) );
255
256 /* Free */
257 free(h->modname);
258 free(h);
259
260 /* All good */
261 return 0;
262 }
263
264 /* Terminate the signal handler thread -- must be called if fd_sig_init was called */
265 void fd_sig_fini(void)
266 {
267 if (!sig_initialized)
268 return;
269
270 /* For each registered handler, stop the thread, free the associated memory */
271 CHECK_POSIX_DO(pthread_mutex_lock(&sig_hdl_lock), /* continue */);
272 while (!FD_IS_LIST_EMPTY(&sig_hdl_list)) {
273 struct sig_hdl * h = (struct sig_hdl *)sig_hdl_list.next;
274
275 /* Unlink */
276 fd_list_unlink(&h->chain);
277
278 /* Stop the catcher thread */
279 CHECK_FCT_DO( fd_thr_term(&h->sig_thr), /* continue */ );
280
281 /* Free */
282 free(h->modname);
283 free(h);
284 }
285 CHECK_POSIX_DO(pthread_mutex_unlock(&sig_hdl_lock), /* continue */);
286
287 /* Destroy the thread attribute */
288 CHECK_POSIX_DO( pthread_attr_destroy(&detached), /* continue */ );
289 return;
290 }
"Welcome to our mercurial repository"