fixed callback_job cancellation for threads waiting in the bus
[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 #include <daemon.h>
28
29 ENUM(signal_names, SIG_ANY, SIG_MAX,
30 /** should not get printed */
31 "SIG_ANY",
32 /** debugging message types */
33 "DMN",
34 "MGR",
35 "IKE",
36 "CHD",
37 "JOB",
38 "CFG",
39 "KNL",
40 "NET",
41 "ENC",
42 "LIB",
43 /** should not get printed */
44 "SIG_DBG_MAX",
45 /** all level0 signals are AUDIT signals */
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 "AUD", "AUD", "AUD",
53 "AUD", "AUD", "AUD",
54 /** should not get printed */
55 "SIG_MAX",
56 );
57
58 typedef struct private_bus_t private_bus_t;
59
60 /**
61 * Private data of a bus_t object.
62 */
63 struct private_bus_t {
64 /**
65 * Public part of a bus_t object.
66 */
67 bus_t public;
68
69 /**
70 * List of registered listeners as entry_t's
71 */
72 linked_list_t *listeners;
73
74 /**
75 * mutex to synchronize active listeners
76 */
77 pthread_mutex_t mutex;
78
79 /**
80 * Thread local storage for a unique, simple thread ID
81 */
82 pthread_key_t thread_id;
83
84 /**
85 * Thread local storage the threads IKE_SA
86 */
87 pthread_key_t thread_sa;
88 };
89
90 typedef struct entry_t entry_t;
91
92 /**
93 * a listener entry, either active or passive
94 */
95 struct entry_t {
96
97 /**
98 * registered listener interface
99 */
100 bus_listener_t *listener;
101
102 /**
103 * is this a active listen() call with a blocking thread
104 */
105 bool blocker;
106
107 /**
108 * condvar where active listeners wait
109 */
110 pthread_cond_t cond;
111 };
112
113 /**
114 * create a listener entry
115 */
116 static entry_t *entry_create(bus_listener_t *listener, bool blocker)
117 {
118 entry_t *this = malloc_thing(entry_t);
119
120 this->listener = listener;
121 this->blocker = blocker;
122 pthread_cond_init(&this->cond, NULL);
123
124 return this;
125 }
126
127 /**
128 * Get a unique thread number for a calling thread. Since
129 * pthread_self returns large and ugly numbers, use this function
130 * for logging; these numbers are incremental starting at 1
131 */
132 static int get_thread_number(private_bus_t *this)
133 {
134 static long current_num = 0;
135 long stored_num;
136
137 stored_num = (long)pthread_getspecific(this->thread_id);
138 if (stored_num == 0)
139 { /* first call of current thread */
140 pthread_setspecific(this->thread_id, (void*)++current_num);
141 return current_num;
142 }
143 else
144 {
145 return stored_num;
146 }
147 }
148
149 /**
150 * Implementation of bus_t.add_listener.
151 */
152 static void add_listener(private_bus_t *this, bus_listener_t *listener)
153 {
154 pthread_mutex_lock(&this->mutex);
155 this->listeners->insert_last(this->listeners, entry_create(listener, FALSE));
156 pthread_mutex_unlock(&this->mutex);
157 }
158
159 /**
160 * Implementation of bus_t.remove_listener.
161 */
162 static void remove_listener(private_bus_t *this, bus_listener_t *listener)
163 {
164 iterator_t *iterator;
165 entry_t *entry;
166
167 pthread_mutex_lock(&this->mutex);
168 iterator = this->listeners->create_iterator(this->listeners, TRUE);
169 while (iterator->iterate(iterator, (void**)&entry))
170 {
171 if (entry->listener == listener)
172 {
173 iterator->remove(iterator);
174 free(entry);
175 break;
176 }
177 }
178 iterator->destroy(iterator);
179 pthread_mutex_unlock(&this->mutex);
180 }
181
182 typedef struct cleanup_data_t cleanup_data_t;
183
184 /**
185 * data to remove a listener using pthread_cleanup handler
186 */
187 struct cleanup_data_t {
188 /** bus instance */
189 private_bus_t *this;
190 /** listener entry */
191 entry_t *entry;
192 };
193
194 /**
195 * pthread_cleanup handler to remove a listener
196 */
197 static void listener_cleanup(cleanup_data_t *data)
198 {
199 iterator_t *iterator;
200 entry_t *entry;
201
202 iterator = data->this->listeners->create_iterator(data->this->listeners, TRUE);
203 while (iterator->iterate(iterator, (void**)&entry))
204 {
205 if (entry == data->entry)
206 {
207 iterator->remove(iterator);
208 free(entry);
209 break;
210 }
211 }
212 iterator->destroy(iterator);
213 }
214
215 /**
216 * Implementation of bus_t.listen.
217 */
218 static void listen_(private_bus_t *this, bus_listener_t *listener, job_t *job)
219 {
220 int old;
221 cleanup_data_t data;
222
223 data.this = this;
224 data.entry = entry_create(listener, TRUE);
225
226 pthread_mutex_lock(&this->mutex);
227 this->listeners->insert_last(this->listeners, data.entry);
228 charon->processor->queue_job(charon->processor, job);
229 pthread_cleanup_push((void*)pthread_mutex_unlock, &this->mutex);
230 pthread_cleanup_push((void*)listener_cleanup, &data);
231 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old);
232 while (data.entry->blocker)
233 {
234 pthread_cond_wait(&data.entry->cond, &this->mutex);
235 }
236 pthread_setcancelstate(old, NULL);
237 pthread_cleanup_pop(FALSE);
238 /* unlock mutex */
239 pthread_cleanup_pop(TRUE);
240 free(data.entry);
241 }
242
243 /**
244 * Implementation of bus_t.set_sa.
245 */
246 static void set_sa(private_bus_t *this, ike_sa_t *ike_sa)
247 {
248 pthread_setspecific(this->thread_sa, ike_sa);
249 }
250
251 /**
252 * Implementation of bus_t.vsignal.
253 */
254 static void vsignal(private_bus_t *this, signal_t signal, level_t level,
255 char* format, va_list args)
256 {
257 iterator_t *iterator;
258 entry_t *entry;
259 ike_sa_t *ike_sa;
260 long thread;
261
262 pthread_mutex_lock(&this->mutex);
263 ike_sa = pthread_getspecific(this->thread_sa);
264 thread = get_thread_number(this);
265
266 iterator = this->listeners->create_iterator(this->listeners, TRUE);
267 while (iterator->iterate(iterator, (void**)&entry))
268 {
269 va_list args_copy;
270 va_copy(args_copy, args);
271 if (!entry->listener->signal(entry->listener, signal, level, thread,
272 ike_sa, format, args_copy))
273 {
274 iterator->remove(iterator);
275 if (entry->blocker)
276 {
277 entry->blocker = FALSE;
278 pthread_cond_signal(&entry->cond);
279 }
280 else
281 {
282 free(entry);
283 }
284 }
285 va_end(args_copy);
286 }
287 iterator->destroy(iterator);
288
289 pthread_mutex_unlock(&this->mutex);
290 }
291
292 /**
293 * Implementation of bus_t.signal.
294 */
295 static void signal_(private_bus_t *this, signal_t signal, level_t level,
296 char* format, ...)
297 {
298 va_list args;
299
300 va_start(args, format);
301 vsignal(this, signal, level, format, args);
302 va_end(args);
303 }
304
305 /**
306 * Implementation of bus_t.destroy.
307 */
308 static void destroy(private_bus_t *this)
309 {
310 this->listeners->destroy_function(this->listeners, free);
311 free(this);
312 }
313
314 /*
315 * Described in header.
316 */
317 bus_t *bus_create()
318 {
319 private_bus_t *this = malloc_thing(private_bus_t);
320
321 this->public.add_listener = (void(*)(bus_t*,bus_listener_t*))add_listener;
322 this->public.remove_listener = (void(*)(bus_t*,bus_listener_t*))remove_listener;
323 this->public.listen = (void(*)(bus_t*, bus_listener_t *listener, job_t *job))listen_;
324 this->public.set_sa = (void(*)(bus_t*,ike_sa_t*))set_sa;
325 this->public.signal = (void(*)(bus_t*,signal_t,level_t,char*,...))signal_;
326 this->public.vsignal = (void(*)(bus_t*,signal_t,level_t,char*,va_list))vsignal;
327 this->public.destroy = (void(*)(bus_t*)) destroy;
328
329 this->listeners = linked_list_create();
330 pthread_mutex_init(&this->mutex, NULL);
331 pthread_key_create(&this->thread_id, NULL);
332 pthread_key_create(&this->thread_sa, NULL);
333
334 return &this->public;
335 }
336