]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libstrongswan/threading/thread.c
Moved debug.[ch] to utils folder
[thirdparty/strongswan.git] / src / libstrongswan / threading / thread.c
CommitLineData
0d5c6a28 1/*
66f16d96 2 * Copyright (C) 2009-2012 Tobias Brunner
0d5c6a28
TB
3 * Hochschule fuer Technik Rapperswil
4 *
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>.
9 *
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
13 * for more details.
14 */
15
16#define _GNU_SOURCE
17#include <pthread.h>
18#include <signal.h>
19#include <semaphore.h>
66f16d96 20
c17f6f96 21#ifdef HAVE_GETTID
66f16d96 22#include <sys/types.h>
c17f6f96 23#include <unistd.h>
17e3a926
TB
24#endif
25
26#ifdef HAVE_SYS_GETTID
c17f6f96 27#include <sys/syscall.h>
66f16d96
TB
28static inline pid_t gettid()
29{
30 return syscall(SYS_gettid);
31}
17e3a926 32#endif
0d5c6a28
TB
33
34#include <library.h>
f05b4272 35#include <utils/debug.h>
0d5c6a28
TB
36
37#include <threading/thread_value.h>
38#include <threading/mutex.h>
12642a68 39#include <collections/linked_list.h>
0d5c6a28
TB
40
41#include "thread.h"
42
43typedef struct private_thread_t private_thread_t;
44
45struct private_thread_t {
46 /**
47 * Public interface.
48 */
49 thread_t public;
50
51 /**
52 * Human-readable ID of this thread.
53 */
54 u_int id;
55
56 /**
57 * ID of the underlying thread.
58 */
59 pthread_t thread_id;
60
61 /**
62 * Main function of this thread (NULL for the main thread).
63 */
64 thread_main_t main;
65
66 /**
67 * Argument for the main function.
68 */
69 void *arg;
70
71 /**
72 * Stack of cleanup handlers.
73 */
74 linked_list_t *cleanup_handlers;
75
76 /**
77 * Mutex to make modifying thread properties safe.
78 */
79 mutex_t *mutex;
80
81 /**
82 * Semaphore used to sync the creation/start of the thread.
83 */
84 sem_t created;
85
86 /**
87 * TRUE if this thread has been detached or joined, i.e. can be cleaned
88 * up after terminating.
89 */
90 bool detached_or_joined;
91
92 /**
93 * TRUE if the threads has terminated (cancelled, via thread_exit or
94 * returned from the main function)
95 */
96 bool terminated;
97
98};
99
100typedef struct {
101 /**
102 * Cleanup callback function.
103 */
104 thread_cleanup_t cleanup;
105
106 /**
107 * Argument provided to the cleanup function.
108 */
109 void *arg;
110
111} cleanup_handler_t;
112
113
114/**
115 * Next thread ID.
116 */
efbb5e8c 117static u_int next_id;
0d5c6a28
TB
118
119/**
120 * Mutex to safely access the next thread ID.
121 */
122static mutex_t *id_mutex;
123
124/**
125 * Store the thread object in a thread-specific value.
126 */
127static thread_value_t *current_thread;
128
c8541efe 129
85202e87
TB
130#ifndef HAVE_PTHREAD_CANCEL
131/* if pthread_cancel is not available, we emulate it using a signal */
132#define SIG_CANCEL (SIGRTMIN+7)
133
134/* the signal handler for SIG_CANCEL uses pthread_exit to terminate the
135 * "cancelled" thread */
136static void cancel_signal_handler(int sig)
137{
138 pthread_exit(NULL);
139}
140#endif
141
0d5c6a28
TB
142
143/**
144 * Destroy an internal thread object.
145 *
146 * @note The mutex of this thread object has to be locked, it gets unlocked
147 * automatically.
148 */
149static void thread_destroy(private_thread_t *this)
150{
151 if (!this->terminated || !this->detached_or_joined)
152 {
153 this->mutex->unlock(this->mutex);
154 return;
155 }
156 this->cleanup_handlers->destroy(this->cleanup_handlers);
157 this->mutex->unlock(this->mutex);
158 this->mutex->destroy(this->mutex);
159 sem_destroy(&this->created);
160 free(this);
161}
162
c8541efe
TB
163METHOD(thread_t, cancel, void,
164 private_thread_t *this)
0d5c6a28
TB
165{
166 this->mutex->lock(this->mutex);
167 if (pthread_equal(this->thread_id, pthread_self()))
168 {
169 this->mutex->unlock(this->mutex);
8b0e0910 170 DBG1(DBG_LIB, "!!! CANNOT CANCEL CURRENT THREAD !!!");
0d5c6a28
TB
171 return;
172 }
85202e87 173#ifdef HAVE_PTHREAD_CANCEL
0d5c6a28 174 pthread_cancel(this->thread_id);
85202e87
TB
175#else
176 pthread_kill(this->thread_id, SIG_CANCEL);
177#endif /* HAVE_PTHREAD_CANCEL */
0d5c6a28
TB
178 this->mutex->unlock(this->mutex);
179}
180
c8541efe
TB
181METHOD(thread_t, kill_, void,
182 private_thread_t *this, int sig)
0d5c6a28
TB
183{
184 this->mutex->lock(this->mutex);
185 if (pthread_equal(this->thread_id, pthread_self()))
186 {
187 /* it might actually be possible to send a signal to pthread_self (there
188 * is an example in raise(3) describing that), the problem is though,
189 * that the thread only returns here after the signal handler has
190 * returned, so depending on the signal, the lock might not get
191 * unlocked. */
192 this->mutex->unlock(this->mutex);
8b0e0910 193 DBG1(DBG_LIB, "!!! CANNOT SEND SIGNAL TO CURRENT THREAD !!!");
0d5c6a28
TB
194 return;
195 }
196 pthread_kill(this->thread_id, sig);
197 this->mutex->unlock(this->mutex);
198}
199
c8541efe
TB
200METHOD(thread_t, detach, void,
201 private_thread_t *this)
0d5c6a28
TB
202{
203 this->mutex->lock(this->mutex);
204 pthread_detach(this->thread_id);
205 this->detached_or_joined = TRUE;
206 thread_destroy(this);
207}
208
c8541efe
TB
209METHOD(thread_t, join, void*,
210 private_thread_t *this)
0d5c6a28
TB
211{
212 pthread_t thread_id;
213 void *val;
51f259a8 214
0d5c6a28
TB
215 this->mutex->lock(this->mutex);
216 if (pthread_equal(this->thread_id, pthread_self()))
217 {
218 this->mutex->unlock(this->mutex);
8b0e0910 219 DBG1(DBG_LIB, "!!! CANNOT JOIN CURRENT THREAD !!!");
0d5c6a28
TB
220 return NULL;
221 }
222 if (this->detached_or_joined)
223 {
224 this->mutex->unlock(this->mutex);
8b0e0910 225 DBG1(DBG_LIB, "!!! CANNOT JOIN DETACHED THREAD !!!");
0d5c6a28
TB
226 return NULL;
227 }
228 thread_id = this->thread_id;
229 this->detached_or_joined = TRUE;
230 if (this->terminated)
231 {
232 /* thread has terminated before the call to join */
233 thread_destroy(this);
234 }
235 else
236 {
237 /* thread_destroy is called when the thread terminates normally */
238 this->mutex->unlock(this->mutex);
239 }
240 pthread_join(thread_id, &val);
51f259a8 241
0d5c6a28
TB
242 return val;
243}
244
245/**
246 * Create an internal thread object.
247 */
248static private_thread_t *thread_create_internal()
249{
c8541efe
TB
250 private_thread_t *this;
251
252 INIT(this,
253 .public = {
254 .cancel = _cancel,
255 .kill = _kill_,
256 .detach = _detach,
257 .join = _join,
258 },
259 .cleanup_handlers = linked_list_create(),
260 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
261 );
0d5c6a28 262 sem_init(&this->created, FALSE, 0);
0d5c6a28
TB
263
264 return this;
265}
266
267/**
268 * Main cleanup function for threads.
269 */
270static void thread_cleanup(private_thread_t *this)
271{
272 cleanup_handler_t *handler;
273 this->mutex->lock(this->mutex);
274 while (this->cleanup_handlers->remove_last(this->cleanup_handlers,
275 (void**)&handler) == SUCCESS)
276 {
277 handler->cleanup(handler->arg);
278 free(handler);
279 }
280 this->terminated = TRUE;
281 thread_destroy(this);
282}
283
284/**
285 * Main function wrapper for threads.
286 */
287static void *thread_main(private_thread_t *this)
288{
289 void *res;
51f259a8 290
0d5c6a28
TB
291 sem_wait(&this->created);
292 current_thread->set(current_thread, this);
293 pthread_cleanup_push((thread_cleanup_t)thread_cleanup, this);
c17f6f96
TB
294
295 /* TODO: this is not 100% portable as pthread_t is an opaque type (i.e.
296 * could be of any size, or even a struct) */
297#ifdef HAVE_GETTID
298 DBG2(DBG_LIB, "created thread %.2d [%u]",
66f16d96 299 this->id, gettid());
c17f6f96
TB
300#else
301 DBG2(DBG_LIB, "created thread %.2d [%lx]",
302 this->id, (u_long)this->thread_id);
303#endif
304
0d5c6a28
TB
305 res = this->main(this->arg);
306 pthread_cleanup_pop(TRUE);
51f259a8 307
0d5c6a28
TB
308 return res;
309}
310
311/**
312 * Described in header.
313 */
314thread_t *thread_create(thread_main_t main, void *arg)
315{
316 private_thread_t *this = thread_create_internal();
51f259a8 317
0d5c6a28
TB
318 this->main = main;
319 this->arg = arg;
320 if (pthread_create(&this->thread_id, NULL, (void*)thread_main, this) != 0)
321 {
8b0e0910 322 DBG1(DBG_LIB, "failed to create thread!");
361f416d 323 this->mutex->lock(this->mutex);
0d5c6a28
TB
324 thread_destroy(this);
325 return NULL;
326 }
327 id_mutex->lock(id_mutex);
328 this->id = next_id++;
329 id_mutex->unlock(id_mutex);
330 sem_post(&this->created);
51f259a8 331
0d5c6a28
TB
332 return &this->public;
333}
334
335/**
336 * Described in header.
337 */
338thread_t *thread_current()
339{
340 return current_thread->get(current_thread);
341}
342
343/**
344 * Described in header.
345 */
346u_int thread_current_id()
347{
348 private_thread_t *this = (private_thread_t*)thread_current();
51f259a8
AS
349
350 return this ? this->id : 0;
0d5c6a28
TB
351}
352
353/**
354 * Described in header.
355 */
356void thread_cleanup_push(thread_cleanup_t cleanup, void *arg)
357{
358 private_thread_t *this = (private_thread_t*)thread_current();
359 cleanup_handler_t *handler;
51f259a8 360
c8541efe
TB
361 INIT(handler,
362 .cleanup = cleanup,
363 .arg = arg,
364 );
365
0d5c6a28 366 this->mutex->lock(this->mutex);
0d5c6a28
TB
367 this->cleanup_handlers->insert_last(this->cleanup_handlers, handler);
368 this->mutex->unlock(this->mutex);
369}
370
371/**
372 * Described in header.
373 */
374void thread_cleanup_pop(bool execute)
375{
376 private_thread_t *this = (private_thread_t*)thread_current();
377 cleanup_handler_t *handler;
51f259a8 378
0d5c6a28
TB
379 this->mutex->lock(this->mutex);
380 if (this->cleanup_handlers->remove_last(this->cleanup_handlers,
381 (void**)&handler) != SUCCESS)
382 {
383 this->mutex->unlock(this->mutex);
8b0e0910 384 DBG1(DBG_LIB, "!!! THREAD CLEANUP ERROR !!!");
0d5c6a28
TB
385 return;
386 }
387 this->mutex->unlock(this->mutex);
388
389 if (execute)
390 {
391 handler->cleanup(handler->arg);
392 }
393 free(handler);
394}
395
396/**
397 * Described in header.
398 */
399bool thread_cancelability(bool enable)
400{
85202e87 401#ifdef HAVE_PTHREAD_CANCEL
0d5c6a28 402 int old;
51f259a8 403
0d5c6a28
TB
404 pthread_setcancelstate(enable ? PTHREAD_CANCEL_ENABLE
405 : PTHREAD_CANCEL_DISABLE, &old);
51f259a8 406
0d5c6a28 407 return old == PTHREAD_CANCEL_ENABLE;
85202e87
TB
408#else
409 sigset_t new, old;
51f259a8 410
85202e87
TB
411 sigemptyset(&new);
412 sigaddset(&new, SIG_CANCEL);
413 pthread_sigmask(enable ? SIG_UNBLOCK : SIG_BLOCK, &new, &old);
51f259a8 414
85202e87
TB
415 return sigismember(&old, SIG_CANCEL) == 0;
416#endif /* HAVE_PTHREAD_CANCEL */
0d5c6a28
TB
417}
418
419/**
420 * Described in header.
421 */
422void thread_cancellation_point()
423{
424 bool old = thread_cancelability(TRUE);
51f259a8 425
85202e87 426#ifdef HAVE_PTHREAD_CANCEL
0d5c6a28 427 pthread_testcancel();
85202e87 428#endif /* HAVE_PTHREAD_CANCEL */
0d5c6a28
TB
429 thread_cancelability(old);
430}
431
432/**
433 * Described in header.
434 */
435void thread_exit(void *val)
436{
437 pthread_exit(val);
438}
439
005b02cb
MW
440/**
441 * A dummy thread value that reserved pthread_key_t value "0". A buggy PKCS#11
442 * library mangles this key, without owning it, so we allocate it for them.
443 */
444static thread_value_t *dummy1;
445
0d5c6a28
TB
446/**
447 * Described in header.
448 */
449void threads_init()
450{
451 private_thread_t *main_thread = thread_create_internal();
51f259a8 452
005b02cb
MW
453 dummy1 = thread_value_create(NULL);
454
efbb5e8c 455 next_id = 1;
0d5c6a28
TB
456 main_thread->id = 0;
457 main_thread->thread_id = pthread_self();
458 current_thread = thread_value_create(NULL);
459 current_thread->set(current_thread, (void*)main_thread);
460 id_mutex = mutex_create(MUTEX_TYPE_DEFAULT);
85202e87
TB
461
462#ifndef HAVE_PTHREAD_CANCEL
463 { /* install a signal handler for our custom SIG_CANCEL */
464 struct sigaction action = {
465 .sa_handler = cancel_signal_handler
466 };
467 sigaction(SIG_CANCEL, &action, NULL);
468 }
469#endif /* HAVE_PTHREAD_CANCEL */
0d5c6a28
TB
470}
471
472/**
473 * Described in header.
474 */
475void threads_deinit()
476{
477 private_thread_t *main_thread = (private_thread_t*)thread_current();
51f259a8 478
005b02cb
MW
479 dummy1->destroy(dummy1);
480
361f416d 481 main_thread->mutex->lock(main_thread->mutex);
0d5c6a28
TB
482 thread_destroy(main_thread);
483 current_thread->destroy(current_thread);
484 id_mutex->destroy(id_mutex);
485}