4 * @brief Implementation of bus_t.
9 * Copyright (C) 2006 Martin Willi
10 * Hochschule fuer Technik Rapperswil
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>.
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
27 ENUM(signal_names
, SIG_ANY
, SIG_MAX
,
28 /** should not get printed */
30 /** debugging message types */
41 /** should not get printed */
43 /** all level0 signals are AUDIT signals */
52 /** should not get printed */
56 typedef struct active_listener_t active_listener_t
;
59 * information for a active listener
61 struct active_listener_t
{
69 * condvar to wait for a signal
77 /** not registered, do not wait for thread */
79 /** registered, if a signal occurs, wait until it is LISTENING */
81 /** listening, deliver signal */
86 * currently processed signals type
91 * verbosity level of the signal
96 * current processed signals thread number
101 * currently processed signals ike_sa
106 * currently processed signals format string
111 * currently processed signals format varargs
117 typedef struct private_bus_t private_bus_t
;
120 * Private data of a bus_t object.
122 struct private_bus_t
{
124 * Public part of a bus_t object.
129 * List of registered listeners implementing the bus_t interface
131 linked_list_t
*listeners
;
134 * List of active listeners with listener_state TRUE
136 linked_list_t
*active_listeners
;
139 * mutex to synchronize active listeners
141 pthread_mutex_t mutex
;
144 * Thread local storage for a unique, simple thread ID
146 pthread_key_t thread_id
;
149 * Thread local storage the threads IKE_SA
151 pthread_key_t thread_sa
;
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
160 static int get_thread_number(private_bus_t
*this)
162 static long current_num
= 0;
163 static long stored_num
;
165 stored_num
= (long)pthread_getspecific(this->thread_id
);
167 { /* first call of current thread */
168 pthread_setspecific(this->thread_id
, (void*)++current_num
);
178 * Implementation of bus_t.add_listener.
180 static void add_listener(private_bus_t
*this, bus_listener_t
*listener
)
182 pthread_mutex_lock(&this->mutex
);
183 this->listeners
->insert_last(this->listeners
, listener
);
184 pthread_mutex_unlock(&this->mutex
);
188 * Implementation of bus_t.remove_listener.
190 static void remove_listener(private_bus_t
*this, bus_listener_t
*listener
)
192 iterator_t
*iterator
;
193 bus_listener_t
*current
;
195 pthread_mutex_lock(&this->mutex
);
196 iterator
= this->listeners
->create_iterator(this->listeners
, TRUE
);
197 while (iterator
->iterate(iterator
, (void**)¤t
))
199 if (current
== listener
)
201 iterator
->remove(iterator
);
205 iterator
->destroy(iterator
);
206 pthread_mutex_unlock(&this->mutex
);
210 * Get the listener object for the calling thread
212 static active_listener_t
*get_active_listener(private_bus_t
*this)
214 active_listener_t
*current
, *found
= NULL
;
215 iterator_t
*iterator
;
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**)¤t
))
221 if (current
->id
== pthread_self())
227 iterator
->destroy(iterator
);
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
);
242 * disable a listener to cleanly clean up
244 static void unregister(active_listener_t
*listener
)
246 listener
->state
= UNREGISTERED
;
247 pthread_cond_broadcast(&listener
->cond
);
251 * Implementation of bus_t.listen.
253 static signal_t
listen_(private_bus_t
*this, level_t
*level
, int *thread
,
254 ike_sa_t
**ike_sa
, char** format
, va_list* args
)
256 active_listener_t
*listener
;
259 pthread_mutex_lock(&this->mutex
);
260 listener
= get_active_listener(this);
261 /* go "listening", say hello to a thread which have a signal for us */
262 listener
->state
= LISTENING
;
263 pthread_cond_broadcast(&listener
->cond
);
264 /* wait until it has us delivered a signal, and go back to "registered".
265 * we allow cancellation here, but must cleanly disable the listener. */
266 pthread_cleanup_push((void*)pthread_mutex_unlock
, &this->mutex
);
267 pthread_cleanup_push((void*)unregister
, listener
);
268 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, &oldstate
);
269 pthread_cond_wait(&listener
->cond
, &this->mutex
);
270 pthread_setcancelstate(oldstate
, NULL
);
271 pthread_cleanup_pop(0);
272 pthread_cleanup_pop(0);
274 pthread_mutex_unlock(&this->mutex
);
276 /* return signal values */
277 *level
= listener
->level
;
278 *thread
= listener
->thread
;
279 *ike_sa
= listener
->ike_sa
;
280 *format
= listener
->format
;
281 va_copy(*args
, listener
->args
);
282 va_end(listener
->args
);
284 return listener
->signal
;
288 * Implementation of bus_t.set_listen_state.
290 static void set_listen_state(private_bus_t
*this, bool active
)
292 active_listener_t
*listener
;
294 pthread_mutex_lock(&this->mutex
);
296 listener
= get_active_listener(this);
299 listener
->state
= REGISTERED
;
303 listener
->state
= UNREGISTERED
;
304 /* say hello to signal emitter; we are finished processing the signal */
305 pthread_cond_broadcast(&listener
->cond
);
308 pthread_mutex_unlock(&this->mutex
);
313 * Implementation of bus_t.set_sa.
315 static void set_sa(private_bus_t
*this, ike_sa_t
*ike_sa
)
317 pthread_setspecific(this->thread_sa
, ike_sa
);
321 * Implementation of bus_t.vsignal.
323 static void vsignal(private_bus_t
*this, signal_t signal
, level_t level
,
324 char* format
, va_list args
)
326 iterator_t
*iterator
;
327 bus_listener_t
*listener
;
328 active_listener_t
*active_listener
;
332 ike_sa
= pthread_getspecific(this->thread_sa
);
333 thread
= get_thread_number(this);
335 pthread_mutex_lock(&this->mutex
);
337 /* do the job for all passive bus_listeners */
338 iterator
= this->listeners
->create_iterator(this->listeners
, TRUE
);
339 while (iterator
->iterate(iterator
, (void**)&listener
))
342 va_copy(args_copy
, args
);
343 if (!listener
->signal(listener
, signal
, level
, thread
,
344 ike_sa
, format
, args_copy
))
346 /* unregister listener if requested */
347 iterator
->remove(iterator
);
351 iterator
->destroy(iterator
);
353 /* wake up all active listeners */
354 iterator
= this->active_listeners
->create_iterator(this->active_listeners
, TRUE
);
355 while (iterator
->iterate(iterator
, (void**)&active_listener
))
357 /* wait until all threads are registered. But if the thread raising
358 * the signal is the same as the one that listens, we skip it.
359 * Otherwise we would deadlock. */
360 while (active_listener
->id
!= pthread_self() &&
361 active_listener
->state
== REGISTERED
)
363 pthread_cond_wait(&active_listener
->cond
, &this->mutex
);
365 /* if thread is listening now, give it the signal to process */
366 if (active_listener
->state
== LISTENING
)
368 active_listener
->level
= level
;
369 active_listener
->thread
= thread
;
370 active_listener
->ike_sa
= ike_sa
;
371 active_listener
->signal
= signal
;
372 active_listener
->format
= format
;
373 va_copy(active_listener
->args
, args
);
374 active_listener
->state
= REGISTERED
;
375 pthread_cond_signal(&active_listener
->cond
);
379 /* we must wait now until all are not in state REGISTERED,
380 * as they may still use our arguments */
381 iterator
->reset(iterator
);
382 while (iterator
->iterate(iterator
, (void**)&active_listener
))
384 /* do not wait for ourself, it won't happen (see above) */
385 while (active_listener
->id
!= pthread_self() &&
386 active_listener
->state
== REGISTERED
)
388 pthread_cond_wait(&active_listener
->cond
, &this->mutex
);
391 iterator
->destroy(iterator
);
393 pthread_mutex_unlock(&this->mutex
);
397 * Implementation of bus_t.signal.
399 static void signal_(private_bus_t
*this, signal_t signal
, level_t level
,
404 va_start(args
, format
);
405 vsignal(this, signal
, level
, format
, args
);
410 * Implementation of bus_t.destroy.
412 static void destroy(private_bus_t
*this)
414 this->active_listeners
->destroy_function(this->active_listeners
, free
);
415 this->listeners
->destroy(this->listeners
);
420 * Described in header.
424 private_bus_t
*this = malloc_thing(private_bus_t
);
426 this->public.add_listener
= (void(*)(bus_t
*,bus_listener_t
*))add_listener
;
427 this->public.remove_listener
= (void(*)(bus_t
*,bus_listener_t
*))remove_listener
;
428 this->public.listen
= (signal_t(*)(bus_t
*,level_t
*,int*,ike_sa_t
**,char**,va_list*))listen_
;
429 this->public.set_listen_state
= (void(*)(bus_t
*,bool))set_listen_state
;
430 this->public.set_sa
= (void(*)(bus_t
*,ike_sa_t
*))set_sa
;
431 this->public.signal
= (void(*)(bus_t
*,signal_t
,level_t
,char*,...))signal_
;
432 this->public.vsignal
= (void(*)(bus_t
*,signal_t
,level_t
,char*,va_list))vsignal
;
433 this->public.destroy
= (void(*)(bus_t
*)) destroy
;
435 this->listeners
= linked_list_create();
436 this->active_listeners
= linked_list_create();
437 pthread_mutex_init(&this->mutex
, NULL
);
438 pthread_key_create(&this->thread_id
, NULL
);
439 pthread_key_create(&this->thread_sa
, NULL
);
441 return &(this->public);