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 */
56 /** should not get printed */
60 typedef struct active_listener_t active_listener_t
;
63 * information for a active listener
65 struct active_listener_t
{
73 * condvar to wait for a signal
81 /** not registered, do not wait for thread */
83 /** registered, if a signal occurs, wait until it is LISTENING */
85 /** listening, deliver signal */
90 * currently processed signals type
95 * verbosity level of the signal
100 * current processed signals thread number
105 * currently processed signals ike_sa
110 * currently processed signals format string
115 * currently processed signals format varargs
121 typedef struct private_bus_t private_bus_t
;
124 * Private data of a bus_t object.
126 struct private_bus_t
{
128 * Public part of a bus_t object.
133 * List of registered listeners implementing the bus_t interface
135 linked_list_t
*listeners
;
138 * List of active listeners with listener_state TRUE
140 linked_list_t
*active_listeners
;
143 * mutex to synchronize active listeners
145 pthread_mutex_t mutex
;
148 * Thread local storage for a unique, simple thread ID
150 pthread_key_t thread_id
;
153 * Thread local storage the threads IKE_SA
155 pthread_key_t thread_sa
;
160 * Get a unique thread number for a calling thread. Since
161 * pthread_self returns large and ugly numbers, use this function
162 * for logging; these numbers are incremental starting at 1
164 static int get_thread_number(private_bus_t
*this)
166 static int current_num
= 0, stored_num
;
168 stored_num
= (int)pthread_getspecific(this->thread_id
);
170 { /* first call of current thread */
171 pthread_setspecific(this->thread_id
, (void*)++current_num
);
181 * Implementation of bus_t.add_listener.
183 static void add_listener(private_bus_t
*this, bus_listener_t
*listener
)
185 pthread_mutex_lock(&this->mutex
);
186 this->listeners
->insert_last(this->listeners
, (void*)listener
);
187 pthread_mutex_unlock(&this->mutex
);
191 * Get the listener object for the calling thread
193 static active_listener_t
*get_active_listener(private_bus_t
*this)
195 active_listener_t
*current
, *found
= NULL
;
196 iterator_t
*iterator
;
198 /* if the thread was here once before, we have a active_listener record */
199 iterator
= this->active_listeners
->create_iterator(this->active_listeners
, TRUE
);
200 while (iterator
->iterate(iterator
, (void**)¤t
))
202 if (current
->id
== pthread_self())
208 iterator
->destroy(iterator
);
212 /* create a new object for a never-seen thread */
213 found
= malloc_thing(active_listener_t
);
214 found
->id
= pthread_self();
215 pthread_cond_init(&found
->cond
, NULL
);
216 this->active_listeners
->insert_last(this->active_listeners
, found
);
223 * Implementation of bus_t.listen.
225 static signal_t
listen_(private_bus_t
*this, level_t
*level
, int *thread
,
226 ike_sa_t
**ike_sa
, char** format
, va_list* args
)
228 active_listener_t
*listener
;
230 pthread_mutex_lock(&this->mutex
);
231 listener
= get_active_listener(this);
232 /* go "listening", say hello to a thread which have a signal for us */
233 listener
->state
= LISTENING
;
234 pthread_cond_broadcast(&listener
->cond
);
235 /* wait until it has us delivered a signal, and go back to "registered" */
236 pthread_cond_wait(&listener
->cond
, &this->mutex
);
237 pthread_mutex_unlock(&this->mutex
);
239 /* return signal values */
240 *level
= listener
->level
;
241 *thread
= listener
->thread
;
242 *ike_sa
= listener
->ike_sa
;
243 *format
= listener
->format
;
244 *args
= listener
->args
;
246 return listener
->signal
;
250 * Implementation of bus_t.set_listen_state.
252 static void set_listen_state(private_bus_t
*this, bool active
)
254 active_listener_t
*listener
;
256 pthread_mutex_lock(&this->mutex
);
258 listener
= get_active_listener(this);
261 listener
->state
= REGISTERED
;
265 listener
->state
= UNREGISTERED
;
266 /* say hello to signal omitter; we are finished processing the signal */
267 pthread_cond_signal(&listener
->cond
);
270 pthread_mutex_unlock(&this->mutex
);
275 * Implementation of bus_t.set_sa.
277 static void set_sa(private_bus_t
*this, ike_sa_t
*ike_sa
)
279 pthread_setspecific(this->thread_sa
, ike_sa
);
283 * Implementation of bus_t.vsignal.
285 static void vsignal(private_bus_t
*this, signal_t signal
, level_t level
,
286 char* format
, va_list args
)
288 iterator_t
*iterator
;
289 bus_listener_t
*listener
;
290 active_listener_t
*active_listener
;
294 ike_sa
= pthread_getspecific(this->thread_sa
);
295 thread
= get_thread_number(this);
297 pthread_mutex_lock(&this->mutex
);
299 /* do the job for all passive bus_listeners */
300 iterator
= this->listeners
->create_iterator(this->listeners
, TRUE
);
301 while (iterator
->iterate(iterator
, (void**)&listener
))
305 va_copy(args_copy
, args
);
306 listener
->signal(listener
, signal
, level
, thread
, ike_sa
, format
, args_copy
);
309 iterator
->destroy(iterator
);
311 /* wake up all active listeners */
312 iterator
= this->active_listeners
->create_iterator(this->active_listeners
, TRUE
);
313 while (iterator
->iterate(iterator
, (void**)&active_listener
))
315 /* wait until it is back */
316 while (active_listener
->state
== REGISTERED
)
318 pthread_cond_wait(&active_listener
->cond
, &this->mutex
);
320 /* if thread is listening now, give it the signal to process */
321 if (active_listener
->state
== LISTENING
)
323 active_listener
->level
= level
;
324 active_listener
->thread
= thread
;
325 active_listener
->ike_sa
= ike_sa
;
326 active_listener
->signal
= signal
;
327 active_listener
->format
= format
;
328 va_copy(active_listener
->args
, args
);
329 active_listener
->state
= REGISTERED
;
330 pthread_cond_signal(&active_listener
->cond
);
334 /* we must wait now until all are not in state REGISTERED,
335 * as they may still use our arguments */
336 iterator
->reset(iterator
);
337 while (iterator
->iterate(iterator
, (void**)&active_listener
))
339 while (active_listener
->state
== REGISTERED
)
341 pthread_cond_wait(&active_listener
->cond
, &this->mutex
);
343 va_end(active_listener
->args
);
345 iterator
->destroy(iterator
);
347 pthread_mutex_unlock(&this->mutex
);
351 * Implementation of bus_t.signal.
353 static void signal_(private_bus_t
*this, signal_t signal
, level_t level
,
358 va_start(args
, format
);
359 vsignal(this, signal
, level
, format
, args
);
364 * Implementation of bus_t.destroy.
366 static void destroy(private_bus_t
*this)
368 active_listener_t
*listener
;
369 while (this->active_listeners
->remove_last(this->active_listeners
,
370 (void**)&listener
) == SUCCESS
)
375 this->active_listeners
->destroy(this->active_listeners
);
376 this->listeners
->destroy(this->listeners
);
381 * Described in header.
385 private_bus_t
*this = malloc_thing(private_bus_t
);
387 this->public.add_listener
= (void(*)(bus_t
*,bus_listener_t
*))add_listener
;
388 this->public.listen
= (signal_t(*)(bus_t
*,level_t
*,int*,ike_sa_t
**,char**,va_list*))listen_
;
389 this->public.set_listen_state
= (void(*)(bus_t
*,bool))set_listen_state
;
390 this->public.set_sa
= (void(*)(bus_t
*,ike_sa_t
*))set_sa
;
391 this->public.signal
= (void(*)(bus_t
*,signal_t
,level_t
,char*,...))signal_
;
392 this->public.vsignal
= (void(*)(bus_t
*,signal_t
,level_t
,char*,va_list))vsignal
;
393 this->public.destroy
= (void(*)(bus_t
*)) destroy
;
395 this->listeners
= linked_list_create();
396 this->active_listeners
= linked_list_create();
397 pthread_mutex_init(&this->mutex
, NULL
);
398 pthread_key_create(&this->thread_id
, NULL
);
399 pthread_key_create(&this->thread_sa
, NULL
);
401 return &(this->public);