proper thread cancellation when using the charon->interfaces
[strongswan.git] / src / charon / bus / bus.c
1 /**
2 * @file bus.c
3 *
4 * @brief Implementation of bus_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2006 Martin Willi
10 * Hochschule fuer Technik Rapperswil
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 */
22
23 #include "bus.h"
24
25 #include <pthread.h>
26
27 ENUM(signal_names, SIG_ANY, SIG_MAX,
28 /** should not get printed */
29 "SIG_ANY",
30 /** debugging message types */
31 "DMN",
32 "MGR",
33 "IKE",
34 "CHD",
35 "JOB",
36 "CFG",
37 "KNL",
38 "NET",
39 "ENC",
40 "LIB",
41 /** should not get printed */
42 "SIG_DBG_MAX",
43 /** all level0 signals are AUDIT signals */
44 "AUD", "AUD", "AUD",
45 "AUD", "AUD", "AUD",
46 "AUD", "AUD", "AUD",
47 "AUD", "AUD", "AUD",
48 "AUD", "AUD", "AUD",
49 "AUD", "AUD", "AUD",
50 "AUD", "AUD", "AUD",
51 "AUD", "AUD", "AUD",
52 /** should not get printed */
53 "SIG_MAX",
54 );
55
56 typedef struct active_listener_t active_listener_t;
57
58 /**
59 * information for a active listener
60 */
61 struct active_listener_t {
62
63 /**
64 * associated thread
65 */
66 pthread_t id;
67
68 /**
69 * condvar to wait for a signal
70 */
71 pthread_cond_t cond;
72
73 /**
74 * state of the thread
75 */
76 enum {
77 /** not registered, do not wait for thread */
78 UNREGISTERED,
79 /** registered, if a signal occurs, wait until it is LISTENING */
80 REGISTERED,
81 /** listening, deliver signal */
82 LISTENING,
83 } state;
84
85 /**
86 * currently processed signals type
87 */
88 signal_t signal;
89
90 /**
91 * verbosity level of the signal
92 */
93 level_t level;
94
95 /**
96 * current processed signals thread number
97 */
98 int thread;
99
100 /**
101 * currently processed signals ike_sa
102 */
103 ike_sa_t *ike_sa;
104
105 /**
106 * currently processed signals format string
107 */
108 char *format;
109
110 /**
111 * currently processed signals format varargs
112 */
113 va_list args;
114
115 };
116
117 typedef struct private_bus_t private_bus_t;
118
119 /**
120 * Private data of a bus_t object.
121 */
122 struct private_bus_t {
123 /**
124 * Public part of a bus_t object.
125 */
126 bus_t public;
127
128 /**
129 * List of registered listeners implementing the bus_t interface
130 */
131 linked_list_t *listeners;
132
133 /**
134 * List of active listeners with listener_state TRUE
135 */
136 linked_list_t *active_listeners;
137
138 /**
139 * mutex to synchronize active listeners
140 */
141 pthread_mutex_t mutex;
142
143 /**
144 * Thread local storage for a unique, simple thread ID
145 */
146 pthread_key_t thread_id;
147
148 /**
149 * Thread local storage the threads IKE_SA
150 */
151 pthread_key_t thread_sa;
152
153 };
154
155 /**
156 * Get a unique thread number for a calling thread. Since
157 * pthread_self returns large and ugly numbers, use this function
158 * for logging; these numbers are incremental starting at 1
159 */
160 static int get_thread_number(private_bus_t *this)
161 {
162 static long current_num = 0;
163 static long stored_num;
164
165 stored_num = (long)pthread_getspecific(this->thread_id);
166 if (stored_num == 0)
167 { /* first call of current thread */
168 pthread_setspecific(this->thread_id, (void*)++current_num);
169 return current_num;
170 }
171 else
172 {
173 return stored_num;
174 }
175 }
176
177 /**
178 * Implementation of bus_t.add_listener.
179 */
180 static void add_listener(private_bus_t *this, bus_listener_t *listener)
181 {
182 pthread_mutex_lock(&this->mutex);
183 this->listeners->insert_last(this->listeners, listener);
184 pthread_mutex_unlock(&this->mutex);
185 }
186
187 /**
188 * Implementation of bus_t.remove_listener.
189 */
190 static void remove_listener(private_bus_t *this, bus_listener_t *listener)
191 {
192 iterator_t *iterator;
193 bus_listener_t *current;
194
195 pthread_mutex_lock(&this->mutex);
196 iterator = this->listeners->create_iterator(this->listeners, TRUE);
197 while (iterator->iterate(iterator, (void**)&current))
198 {
199 if (current == listener)
200 {
201 iterator->remove(iterator);
202 break;
203 }
204 }
205 iterator->destroy(iterator);
206 pthread_mutex_unlock(&this->mutex);
207 }
208
209 /**
210 * Get the listener object for the calling thread
211 */
212 static active_listener_t *get_active_listener(private_bus_t *this)
213 {
214 active_listener_t *current, *found = NULL;
215 iterator_t *iterator;
216
217 /* if the thread was here once before, we have a active_listener record */
218 iterator = this->active_listeners->create_iterator(this->active_listeners, TRUE);
219 while (iterator->iterate(iterator, (void**)&current))
220 {
221 if (current->id == pthread_self())
222 {
223 found = current;
224 break;
225 }
226 }
227 iterator->destroy(iterator);
228
229 if (found == NULL)
230 {
231 /* create a new object for a never-seen thread */
232 found = malloc_thing(active_listener_t);
233 found->id = pthread_self();
234 pthread_cond_init(&found->cond, NULL);
235 this->active_listeners->insert_last(this->active_listeners, found);
236 }
237
238 return found;
239 }
240
241 typedef struct cancel_info_t cancel_info_t;
242
243 /**
244 * cancellation info to cancel a listening operation cleanly
245 */
246 struct cancel_info_t {
247 /**
248 * mutex to unlock on cancellation
249 */
250 pthread_mutex_t *mutex;
251
252 /**
253 * listener to unregister
254 */
255 active_listener_t *listener;
256 };
257
258 /**
259 * disable a listener to cleanly clean up
260 */
261 static void unregister(cancel_info_t *info)
262 {
263 info->listener->state = UNREGISTERED;
264 pthread_mutex_unlock(info->mutex);
265 }
266
267 /**
268 * Implementation of bus_t.listen.
269 */
270 static signal_t listen_(private_bus_t *this, level_t *level, int *thread,
271 ike_sa_t **ike_sa, char** format, va_list* args)
272 {
273 active_listener_t *listener;
274 int oldstate;
275 cancel_info_t info;
276
277 pthread_mutex_lock(&this->mutex);
278 listener = get_active_listener(this);
279 /* go "listening", say hello to a thread which have a signal for us */
280 listener->state = LISTENING;
281 pthread_cond_broadcast(&listener->cond);
282 /* wait until it has us delivered a signal, and go back to "registered".
283 * we allow cancellation here, but must cleanly disable the listener. */
284 info.mutex = &this->mutex;
285 info.listener = listener;
286 pthread_cleanup_push((void*)unregister, &info);
287 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
288 pthread_cond_wait(&listener->cond, &this->mutex);
289 pthread_setcancelstate(oldstate, NULL);
290 pthread_cleanup_pop(0);
291
292 pthread_mutex_unlock(&this->mutex);
293
294 /* return signal values */
295 *level = listener->level;
296 *thread = listener->thread;
297 *ike_sa = listener->ike_sa;
298 *format = listener->format;
299 va_copy(*args, listener->args);
300 va_end(listener->args);
301
302 return listener->signal;
303 }
304
305 /**
306 * Implementation of bus_t.set_listen_state.
307 */
308 static void set_listen_state(private_bus_t *this, bool active)
309 {
310 active_listener_t *listener;
311
312 pthread_mutex_lock(&this->mutex);
313
314 listener = get_active_listener(this);
315 if (active)
316 {
317 listener->state = REGISTERED;
318 }
319 else
320 {
321 listener->state = UNREGISTERED;
322 /* say hello to signal emitter; we are finished processing the signal */
323 pthread_cond_signal(&listener->cond);
324 }
325
326 pthread_mutex_unlock(&this->mutex);
327 }
328
329
330 /**
331 * Implementation of bus_t.set_sa.
332 */
333 static void set_sa(private_bus_t *this, ike_sa_t *ike_sa)
334 {
335 pthread_setspecific(this->thread_sa, ike_sa);
336 }
337
338 /**
339 * Implementation of bus_t.vsignal.
340 */
341 static void vsignal(private_bus_t *this, signal_t signal, level_t level,
342 char* format, va_list args)
343 {
344 iterator_t *iterator;
345 bus_listener_t *listener;
346 active_listener_t *active_listener;
347 ike_sa_t *ike_sa;
348 long thread;
349
350 ike_sa = pthread_getspecific(this->thread_sa);
351 thread = get_thread_number(this);
352
353 pthread_mutex_lock(&this->mutex);
354
355 /* do the job for all passive bus_listeners */
356 iterator = this->listeners->create_iterator(this->listeners, TRUE);
357 while (iterator->iterate(iterator, (void**)&listener))
358 {
359 va_list args_copy;
360 va_copy(args_copy, args);
361 if (!listener->signal(listener, signal, level, thread,
362 ike_sa, format, args_copy))
363 {
364 /* unregister listener if requested */
365 iterator->remove(iterator);
366 }
367 va_end(args_copy);
368 }
369 iterator->destroy(iterator);
370
371 /* wake up all active listeners */
372 iterator = this->active_listeners->create_iterator(this->active_listeners, TRUE);
373 while (iterator->iterate(iterator, (void**)&active_listener))
374 {
375 /* wait until all threads are registered. But if the thread raising
376 * the signal is the same as the one that listens, we skip it.
377 * Otherwise we would deadlock. */
378 while (active_listener->id != pthread_self() &&
379 active_listener->state == REGISTERED)
380 {
381 pthread_cond_wait(&active_listener->cond, &this->mutex);
382 }
383 /* if thread is listening now, give it the signal to process */
384 if (active_listener->state == LISTENING)
385 {
386 active_listener->level = level;
387 active_listener->thread = thread;
388 active_listener->ike_sa = ike_sa;
389 active_listener->signal = signal;
390 active_listener->format = format;
391 va_copy(active_listener->args, args);
392 active_listener->state = REGISTERED;
393 pthread_cond_signal(&active_listener->cond);
394 }
395 }
396
397 /* we must wait now until all are not in state REGISTERED,
398 * as they may still use our arguments */
399 iterator->reset(iterator);
400 while (iterator->iterate(iterator, (void**)&active_listener))
401 {
402 /* do not wait for ourself, it won't happen (see above) */
403 while (active_listener->id != pthread_self() &&
404 active_listener->state == REGISTERED)
405 {
406 pthread_cond_wait(&active_listener->cond, &this->mutex);
407 }
408 }
409 iterator->destroy(iterator);
410
411 pthread_mutex_unlock(&this->mutex);
412 }
413
414 /**
415 * Implementation of bus_t.signal.
416 */
417 static void signal_(private_bus_t *this, signal_t signal, level_t level,
418 char* format, ...)
419 {
420 va_list args;
421
422 va_start(args, format);
423 vsignal(this, signal, level, format, args);
424 va_end(args);
425 }
426
427 /**
428 * Implementation of bus_t.destroy.
429 */
430 static void destroy(private_bus_t *this)
431 {
432 this->active_listeners->destroy_function(this->active_listeners, free);
433 this->listeners->destroy(this->listeners);
434 free(this);
435 }
436
437 /*
438 * Described in header.
439 */
440 bus_t *bus_create()
441 {
442 private_bus_t *this = malloc_thing(private_bus_t);
443
444 this->public.add_listener = (void(*)(bus_t*,bus_listener_t*))add_listener;
445 this->public.remove_listener = (void(*)(bus_t*,bus_listener_t*))remove_listener;
446 this->public.listen = (signal_t(*)(bus_t*,level_t*,int*,ike_sa_t**,char**,va_list*))listen_;
447 this->public.set_listen_state = (void(*)(bus_t*,bool))set_listen_state;
448 this->public.set_sa = (void(*)(bus_t*,ike_sa_t*))set_sa;
449 this->public.signal = (void(*)(bus_t*,signal_t,level_t,char*,...))signal_;
450 this->public.vsignal = (void(*)(bus_t*,signal_t,level_t,char*,va_list))vsignal;
451 this->public.destroy = (void(*)(bus_t*)) destroy;
452
453 this->listeners = linked_list_create();
454 this->active_listeners = linked_list_create();
455 pthread_mutex_init(&this->mutex, NULL);
456 pthread_key_create(&this->thread_id, NULL);
457 pthread_key_create(&this->thread_sa, NULL);
458
459 return &(this->public);
460 }