2 * Copyright (C) 2006 Martin Willi
3 * Hochschule fuer Technik Rapperswil
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 #include <utils/mutex.h>
25 ENUM(signal_names
, SIG_ANY
, SIG_MAX
,
26 /** should not get printed */
28 /** debugging message types */
39 /** should not get printed */
41 /** all level0 signals are AUDIT signals */
50 /** should not get printed */
54 typedef struct private_bus_t private_bus_t
;
57 * Private data of a bus_t object.
59 struct private_bus_t
{
61 * Public part of a bus_t object.
66 * List of registered listeners as entry_t's
68 linked_list_t
*listeners
;
71 * mutex to synchronize active listeners, recursively
76 * Thread local storage for a unique, simple thread ID
78 pthread_key_t thread_id
;
81 * Thread local storage the threads IKE_SA
83 pthread_key_t thread_sa
;
86 typedef struct entry_t entry_t
;
89 * a listener entry, either active or passive
94 * registered listener interface
96 bus_listener_t
*listener
;
99 * is this a active listen() call with a blocking thread
104 * condvar where active listeners wait
110 * create a listener entry
112 static entry_t
*entry_create(bus_listener_t
*listener
, bool blocker
)
114 entry_t
*this = malloc_thing(entry_t
);
116 this->listener
= listener
;
117 this->blocker
= blocker
;
118 this->condvar
= condvar_create(CONDVAR_DEFAULT
);
126 static void entry_destroy(entry_t
*entry
)
128 entry
->condvar
->destroy(entry
->condvar
);
133 * Get a unique thread number for a calling thread. Since
134 * pthread_self returns large and ugly numbers, use this function
135 * for logging; these numbers are incremental starting at 1
137 static int get_thread_number(private_bus_t
*this)
139 static long current_num
= 0;
142 stored_num
= (long)pthread_getspecific(this->thread_id
);
144 { /* first call of current thread */
145 pthread_setspecific(this->thread_id
, (void*)++current_num
);
155 * Implementation of bus_t.add_listener.
157 static void add_listener(private_bus_t
*this, bus_listener_t
*listener
)
159 this->mutex
->lock(this->mutex
);
160 this->listeners
->insert_last(this->listeners
, entry_create(listener
, FALSE
));
161 this->mutex
->unlock(this->mutex
);
165 * Implementation of bus_t.remove_listener.
167 static void remove_listener(private_bus_t
*this, bus_listener_t
*listener
)
169 iterator_t
*iterator
;
172 this->mutex
->lock(this->mutex
);
173 iterator
= this->listeners
->create_iterator(this->listeners
, TRUE
);
174 while (iterator
->iterate(iterator
, (void**)&entry
))
176 if (entry
->listener
== listener
)
178 iterator
->remove(iterator
);
179 entry_destroy(entry
);
183 iterator
->destroy(iterator
);
184 this->mutex
->unlock(this->mutex
);
187 typedef struct cleanup_data_t cleanup_data_t
;
190 * data to remove a listener using pthread_cleanup handler
192 struct cleanup_data_t
{
195 /** listener entry */
200 * pthread_cleanup handler to remove a listener
202 static void listener_cleanup(cleanup_data_t
*data
)
204 iterator_t
*iterator
;
207 iterator
= data
->this->listeners
->create_iterator(data
->this->listeners
, TRUE
);
208 while (iterator
->iterate(iterator
, (void**)&entry
))
210 if (entry
== data
->entry
)
212 iterator
->remove(iterator
);
213 entry_destroy(entry
);
217 iterator
->destroy(iterator
);
221 * Implementation of bus_t.listen.
223 static void listen_(private_bus_t
*this, bus_listener_t
*listener
, job_t
*job
)
229 data
.entry
= entry_create(listener
, TRUE
);
231 this->mutex
->lock(this->mutex
);
232 this->listeners
->insert_last(this->listeners
, data
.entry
);
233 charon
->processor
->queue_job(charon
->processor
, job
);
234 pthread_cleanup_push((void*)this->mutex
->unlock
, this->mutex
);
235 pthread_cleanup_push((void*)listener_cleanup
, &data
);
236 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, &old
);
237 while (data
.entry
->blocker
)
239 data
.entry
->condvar
->wait(data
.entry
->condvar
, this->mutex
);
241 pthread_setcancelstate(old
, NULL
);
242 pthread_cleanup_pop(FALSE
);
244 pthread_cleanup_pop(TRUE
);
245 entry_destroy(data
.entry
);
249 * Implementation of bus_t.set_sa.
251 static void set_sa(private_bus_t
*this, ike_sa_t
*ike_sa
)
253 pthread_setspecific(this->thread_sa
, ike_sa
);
258 * Implementation of bus_t.vsignal.
260 static void vsignal(private_bus_t
*this, signal_t signal
, level_t level
,
261 char* format
, va_list args
)
263 iterator_t
*iterator
;
268 this->mutex
->lock(this->mutex
);
269 ike_sa
= pthread_getspecific(this->thread_sa
);
270 thread
= get_thread_number(this);
272 iterator
= this->listeners
->create_iterator(this->listeners
, TRUE
);
273 while (iterator
->iterate(iterator
, (void**)&entry
))
276 va_copy(args_copy
, args
);
277 if (!entry
->listener
->signal(entry
->listener
, signal
, level
, thread
,
278 ike_sa
, format
, args_copy
))
280 iterator
->remove(iterator
);
283 entry
->blocker
= FALSE
;
284 entry
->condvar
->signal(entry
->condvar
);
288 entry_destroy(entry
);
293 iterator
->destroy(iterator
);
295 this->mutex
->unlock(this->mutex
);
299 * Implementation of bus_t.signal.
301 static void signal_(private_bus_t
*this, signal_t signal
, level_t level
,
306 va_start(args
, format
);
307 vsignal(this, signal
, level
, format
, args
);
312 * Implementation of bus_t.destroy.
314 static void destroy(private_bus_t
*this)
316 this->mutex
->destroy(this->mutex
);
317 this->listeners
->destroy_function(this->listeners
, (void*)entry_destroy
);
322 * Described in header.
326 private_bus_t
*this = malloc_thing(private_bus_t
);
328 this->public.add_listener
= (void(*)(bus_t
*,bus_listener_t
*))add_listener
;
329 this->public.remove_listener
= (void(*)(bus_t
*,bus_listener_t
*))remove_listener
;
330 this->public.listen
= (void(*)(bus_t
*, bus_listener_t
*listener
, job_t
*job
))listen_
;
331 this->public.set_sa
= (void(*)(bus_t
*,ike_sa_t
*))set_sa
;
332 this->public.signal
= (void(*)(bus_t
*,signal_t
,level_t
,char*,...))signal_
;
333 this->public.vsignal
= (void(*)(bus_t
*,signal_t
,level_t
,char*,va_list))vsignal
;
334 this->public.destroy
= (void(*)(bus_t
*)) destroy
;
336 this->listeners
= linked_list_create();
337 this->mutex
= mutex_create(MUTEX_DEFAULT
);
338 pthread_key_create(&this->thread_id
, NULL
);
339 pthread_key_create(&this->thread_sa
, NULL
);
341 return &this->public;