summaryrefslogtreecommitdiff
path: root/src/libstrongswan/threading
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstrongswan/threading')
-rw-r--r--src/libstrongswan/threading/condvar.h96
-rw-r--r--src/libstrongswan/threading/lock_profiler.h102
-rw-r--r--src/libstrongswan/threading/mutex.c375
-rw-r--r--src/libstrongswan/threading/mutex.h68
-rw-r--r--src/libstrongswan/threading/rwlock.c327
-rw-r--r--src/libstrongswan/threading/rwlock.h80
-rw-r--r--src/libstrongswan/threading/thread.c440
-rw-r--r--src/libstrongswan/threading/thread.h187
-rw-r--r--src/libstrongswan/threading/thread_value.c78
-rw-r--r--src/libstrongswan/threading/thread_value.h68
10 files changed, 1821 insertions, 0 deletions
diff --git a/src/libstrongswan/threading/condvar.h b/src/libstrongswan/threading/condvar.h
new file mode 100644
index 000000000..48c949c7c
--- /dev/null
+++ b/src/libstrongswan/threading/condvar.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2008-2009 Tobias Brunner
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup condvar condvar
+ * @{ @ingroup threading
+ */
+
+#ifndef THREADING_CONDVAR_H_
+#define THREADING_CONDVAR_H_
+
+typedef struct condvar_t condvar_t;
+typedef enum condvar_type_t condvar_type_t;
+
+#include "mutex.h"
+
+/**
+ * Type of condvar.
+ */
+enum condvar_type_t {
+ /** default condvar */
+ CONDVAR_TYPE_DEFAULT = 0,
+};
+
+/**
+ * Condvar wrapper to use in conjunction with mutex_t.
+ */
+struct condvar_t {
+
+ /**
+ * Wait on a condvar until it gets signalized.
+ *
+ * @param mutex mutex to release while waiting
+ */
+ void (*wait)(condvar_t *this, mutex_t *mutex);
+
+ /**
+ * Wait on a condvar until it gets signalized, or times out.
+ *
+ * @param mutex mutex to release while waiting
+ * @param timeout timeout im ms
+ * @return TRUE if timed out, FALSE otherwise
+ */
+ bool (*timed_wait)(condvar_t *this, mutex_t *mutex, u_int timeout);
+
+ /**
+ * Wait on a condvar until it gets signalized, or times out.
+ *
+ * The passed timeval should be calculated based on the time_monotonic()
+ * function.
+ *
+ * @param mutex mutex to release while waiting
+ * @param tv absolute time until timeout
+ * @return TRUE if timed out, FALSE otherwise
+ */
+ bool (*timed_wait_abs)(condvar_t *this, mutex_t *mutex, timeval_t tv);
+
+ /**
+ * Wake up a single thread in a condvar.
+ */
+ void (*signal)(condvar_t *this);
+
+ /**
+ * Wake up all threads in a condvar.
+ */
+ void (*broadcast)(condvar_t *this);
+
+ /**
+ * Destroy a condvar and free its resources.
+ */
+ void (*destroy)(condvar_t *this);
+};
+
+/**
+ * Create a condvar instance.
+ *
+ * @param type type of condvar to create
+ * @return condvar instance
+ */
+condvar_t *condvar_create(condvar_type_t type);
+
+#endif /** THREADING_CONDVAR_H_ @} */
+
diff --git a/src/libstrongswan/threading/lock_profiler.h b/src/libstrongswan/threading/lock_profiler.h
new file mode 100644
index 000000000..b64453ba1
--- /dev/null
+++ b/src/libstrongswan/threading/lock_profiler.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2008 Tobias Brunner
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef THREADING_LOCK_PROFILER_H_
+#define THREADING_LOCK_PROFILER_H_
+
+#ifdef LOCK_PROFILER
+
+#include <time.h>
+
+/**
+ * Do not report mutexes with an overall waiting time smaller than this (in us)
+ */
+#define PROFILE_WAIT_TRESHHOLD 10000
+
+/**
+ * Do not report mutexes with an overall lock count smaller than this
+ */
+#define PROFILE_LOCK_TRESHHOLD 1000
+
+#include <utils/backtrace.h>
+
+typedef struct lock_profile_t lock_profile_t;
+
+struct lock_profile_t {
+ /**
+ * how long threads have waited for the lock in this mutex so far
+ */
+ timeval_t waited;
+
+ /**
+ * How many times the lock has been invoked
+ */
+ u_int locked;
+
+ /**
+ * backtrace where mutex has been created
+ */
+ backtrace_t *backtrace;
+};
+
+/**
+ * Print and cleanup mutex profiler
+ */
+static inline void profiler_cleanup(lock_profile_t *profile)
+{
+ if (profile->waited.tv_sec > 0 ||
+ profile->waited.tv_usec > PROFILE_WAIT_TRESHHOLD ||
+ profile->locked > PROFILE_LOCK_TRESHHOLD)
+ {
+ fprintf(stderr, "%d.%03ds / %d times in lock created at:",
+ profile->waited.tv_sec, profile->waited.tv_usec, profile->locked);
+ profile->backtrace->log(profile->backtrace, stderr);
+ }
+ profile->backtrace->destroy(profile->backtrace);
+}
+
+/**
+ * Initialize mutex profiler
+ */
+static inline void profiler_init(lock_profile_t *profile)
+{
+ profile->backtrace = backtrace_create(2);
+ timerclear(&profile->waited);
+ profile->locked = 0;
+}
+
+#define profiler_start(profile) { \
+ struct timeval _start, _end, _diff; \
+ (profile)->locked++; \
+ time_monotonic(&_start);
+
+#define profiler_end(profile) \
+ time_monotonic(&_end); \
+ timersub(&_end, &_start, &_diff); \
+ timeradd(&(profile)->waited, &_diff, &(profile)->waited); }
+
+#else /* !LOCK_PROFILER */
+
+#define lock_profile_t struct {}
+#define profiler_cleanup(...) {}
+#define profiler_init(...) {}
+#define profiler_start(...) {}
+#define profiler_end(...) {}
+
+#endif /* LOCK_PROFILER */
+
+#endif /* THREADING_LOCK_PROFILER_H_ */
+
diff --git a/src/libstrongswan/threading/mutex.c b/src/libstrongswan/threading/mutex.c
new file mode 100644
index 000000000..a35695624
--- /dev/null
+++ b/src/libstrongswan/threading/mutex.c
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2008-2009 Tobias Brunner
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#define _GNU_SOURCE
+#include <pthread.h>
+#include <stdint.h>
+#include <time.h>
+#include <errno.h>
+
+#include <library.h>
+#include <debug.h>
+
+#include "condvar.h"
+#include "mutex.h"
+#include "lock_profiler.h"
+
+typedef struct private_mutex_t private_mutex_t;
+typedef struct private_r_mutex_t private_r_mutex_t;
+typedef struct private_condvar_t private_condvar_t;
+
+/**
+ * private data of mutex
+ */
+struct private_mutex_t {
+
+ /**
+ * public functions
+ */
+ mutex_t public;
+
+ /**
+ * wrapped pthread mutex
+ */
+ pthread_mutex_t mutex;
+
+ /**
+ * is this a recursiv emutex, implementing private_r_mutex_t?
+ */
+ bool recursive;
+
+ /**
+ * profiling info, if enabled
+ */
+ lock_profile_t profile;
+};
+
+/**
+ * private data of mutex, extended by recursive locking information
+ */
+struct private_r_mutex_t {
+
+ /**
+ * Extends private_mutex_t
+ */
+ private_mutex_t generic;
+
+ /**
+ * thread which currently owns mutex
+ */
+ pthread_t thread;
+
+ /**
+ * times we have locked the lock, stored per thread
+ */
+ pthread_key_t times;
+};
+
+/**
+ * private data of condvar
+ */
+struct private_condvar_t {
+
+ /**
+ * public functions
+ */
+ condvar_t public;
+
+ /**
+ * wrapped pthread condvar
+ */
+ pthread_cond_t condvar;
+
+};
+
+
+
+/**
+ * Implementation of mutex_t.lock.
+ */
+static void lock(private_mutex_t *this)
+{
+ int err;
+
+ profiler_start(&this->profile);
+ err = pthread_mutex_lock(&this->mutex);
+ if (err)
+ {
+ DBG1("!!! MUTEX LOCK ERROR: %s !!!", strerror(err));
+ }
+ profiler_end(&this->profile);
+}
+
+/**
+ * Implementation of mutex_t.unlock.
+ */
+static void unlock(private_mutex_t *this)
+{
+ int err;
+
+ err = pthread_mutex_unlock(&this->mutex);
+ if (err)
+ {
+ DBG1("!!! MUTEX UNLOCK ERROR: %s !!!", strerror(err));
+ }
+}
+
+/**
+ * Implementation of mutex_t.lock.
+ */
+static void lock_r(private_r_mutex_t *this)
+{
+ pthread_t self = pthread_self();
+
+ if (this->thread == self)
+ {
+ uintptr_t times;
+
+ /* times++ */
+ times = (uintptr_t)pthread_getspecific(this->times);
+ pthread_setspecific(this->times, (void*)times + 1);
+ }
+ else
+ {
+ lock(&this->generic);
+ this->thread = self;
+ /* times = 1 */
+ pthread_setspecific(this->times, (void*)1);
+ }
+}
+
+/**
+ * Implementation of mutex_t.unlock.
+ */
+static void unlock_r(private_r_mutex_t *this)
+{
+ uintptr_t times;
+
+ /* times-- */
+ times = (uintptr_t)pthread_getspecific(this->times);
+ pthread_setspecific(this->times, (void*)--times);
+
+ if (times == 0)
+ {
+ this->thread = 0;
+ unlock(&this->generic);
+ }
+}
+
+/**
+ * Implementation of mutex_t.destroy
+ */
+static void mutex_destroy(private_mutex_t *this)
+{
+ profiler_cleanup(&this->profile);
+ pthread_mutex_destroy(&this->mutex);
+ free(this);
+}
+
+/**
+ * Implementation of mutex_t.destroy for recursive mutex'
+ */
+static void mutex_destroy_r(private_r_mutex_t *this)
+{
+ profiler_cleanup(&this->generic.profile);
+ pthread_mutex_destroy(&this->generic.mutex);
+ pthread_key_delete(this->times);
+ free(this);
+}
+
+/*
+ * see header file
+ */
+mutex_t *mutex_create(mutex_type_t type)
+{
+ switch (type)
+ {
+ case MUTEX_TYPE_RECURSIVE:
+ {
+ private_r_mutex_t *this = malloc_thing(private_r_mutex_t);
+
+ this->generic.public.lock = (void(*)(mutex_t*))lock_r;
+ this->generic.public.unlock = (void(*)(mutex_t*))unlock_r;
+ this->generic.public.destroy = (void(*)(mutex_t*))mutex_destroy_r;
+
+ pthread_mutex_init(&this->generic.mutex, NULL);
+ pthread_key_create(&this->times, NULL);
+ this->generic.recursive = TRUE;
+ profiler_init(&this->generic.profile);
+ this->thread = 0;
+
+ return &this->generic.public;
+ }
+ case MUTEX_TYPE_DEFAULT:
+ default:
+ {
+ private_mutex_t *this = malloc_thing(private_mutex_t);
+
+ this->public.lock = (void(*)(mutex_t*))lock;
+ this->public.unlock = (void(*)(mutex_t*))unlock;
+ this->public.destroy = (void(*)(mutex_t*))mutex_destroy;
+
+ pthread_mutex_init(&this->mutex, NULL);
+ this->recursive = FALSE;
+ profiler_init(&this->profile);
+
+ return &this->public;
+ }
+ }
+}
+
+
+
+/**
+ * Implementation of condvar_t.wait.
+ */
+static void _wait(private_condvar_t *this, private_mutex_t *mutex)
+{
+ if (mutex->recursive)
+ {
+ private_r_mutex_t* recursive = (private_r_mutex_t*)mutex;
+
+ /* mutex owner gets cleared during condvar wait */
+ recursive->thread = 0;
+ pthread_cond_wait(&this->condvar, &mutex->mutex);
+ recursive->thread = pthread_self();
+ }
+ else
+ {
+ pthread_cond_wait(&this->condvar, &mutex->mutex);
+ }
+}
+
+/* use the monotonic clock based version of this function if available */
+#ifdef HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC
+#define pthread_cond_timedwait pthread_cond_timedwait_monotonic
+#endif
+
+/**
+ * Implementation of condvar_t.timed_wait_abs.
+ */
+static bool timed_wait_abs(private_condvar_t *this, private_mutex_t *mutex,
+ timeval_t time)
+{
+ struct timespec ts;
+ bool timed_out;
+
+ ts.tv_sec = time.tv_sec;
+ ts.tv_nsec = time.tv_usec * 1000;
+
+ if (mutex->recursive)
+ {
+ private_r_mutex_t* recursive = (private_r_mutex_t*)mutex;
+
+ recursive->thread = 0;
+ timed_out = pthread_cond_timedwait(&this->condvar, &mutex->mutex,
+ &ts) == ETIMEDOUT;
+ recursive->thread = pthread_self();
+ }
+ else
+ {
+ timed_out = pthread_cond_timedwait(&this->condvar, &mutex->mutex,
+ &ts) == ETIMEDOUT;
+ }
+ return timed_out;
+}
+
+/**
+ * Implementation of condvar_t.timed_wait.
+ */
+static bool timed_wait(private_condvar_t *this, private_mutex_t *mutex,
+ u_int timeout)
+{
+ timeval_t tv;
+ u_int s, ms;
+
+ time_monotonic(&tv);
+
+ s = timeout / 1000;
+ ms = timeout % 1000;
+
+ tv.tv_sec += s;
+ tv.tv_usec += ms * 1000;
+
+ if (tv.tv_usec > 1000000 /* 1s */)
+ {
+ tv.tv_usec -= 1000000;
+ tv.tv_sec++;
+ }
+ return timed_wait_abs(this, mutex, tv);
+}
+
+/**
+ * Implementation of condvar_t.signal.
+ */
+static void _signal(private_condvar_t *this)
+{
+ pthread_cond_signal(&this->condvar);
+}
+
+/**
+ * Implementation of condvar_t.broadcast.
+ */
+static void broadcast(private_condvar_t *this)
+{
+ pthread_cond_broadcast(&this->condvar);
+}
+
+/**
+ * Implementation of condvar_t.destroy
+ */
+static void condvar_destroy(private_condvar_t *this)
+{
+ pthread_cond_destroy(&this->condvar);
+ free(this);
+}
+
+/*
+ * see header file
+ */
+condvar_t *condvar_create(condvar_type_t type)
+{
+ switch (type)
+ {
+ case CONDVAR_TYPE_DEFAULT:
+ default:
+ {
+ private_condvar_t *this = malloc_thing(private_condvar_t);
+
+ this->public.wait = (void(*)(condvar_t*, mutex_t *mutex))_wait;
+ this->public.timed_wait = (bool(*)(condvar_t*, mutex_t *mutex, u_int timeout))timed_wait;
+ this->public.timed_wait_abs = (bool(*)(condvar_t*, mutex_t *mutex, timeval_t time))timed_wait_abs;
+ this->public.signal = (void(*)(condvar_t*))_signal;
+ this->public.broadcast = (void(*)(condvar_t*))broadcast;
+ this->public.destroy = (void(*)(condvar_t*))condvar_destroy;
+
+#ifdef HAVE_PTHREAD_CONDATTR_INIT
+ {
+ pthread_condattr_t condattr;
+ pthread_condattr_init(&condattr);
+#ifdef HAVE_CONDATTR_CLOCK_MONOTONIC
+ pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC);
+#endif
+ pthread_cond_init(&this->condvar, &condattr);
+ pthread_condattr_destroy(&condattr);
+ }
+#endif
+
+ return &this->public;
+ }
+ }
+}
+
diff --git a/src/libstrongswan/threading/mutex.h b/src/libstrongswan/threading/mutex.h
new file mode 100644
index 000000000..ac36b6a25
--- /dev/null
+++ b/src/libstrongswan/threading/mutex.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2008-2009 Tobias Brunner
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup mutex mutex
+ * @{ @ingroup threading
+ */
+
+#ifndef THREADING_MUTEX_H_
+#define THREADING_MUTEX_H_
+
+typedef struct mutex_t mutex_t;
+typedef enum mutex_type_t mutex_type_t;
+
+/**
+ * Type of mutex.
+ */
+enum mutex_type_t {
+ /** default mutex */
+ MUTEX_TYPE_DEFAULT = 0,
+ /** allow recursive locking of the mutex */
+ MUTEX_TYPE_RECURSIVE = 1,
+};
+
+/**
+ * Mutex wrapper implements simple, portable and advanced mutex functions.
+ */
+struct mutex_t {
+
+ /**
+ * Acquire the lock to the mutex.
+ */
+ void (*lock)(mutex_t *this);
+
+ /**
+ * Release the lock on the mutex.
+ */
+ void (*unlock)(mutex_t *this);
+
+ /**
+ * Destroy a mutex instance.
+ */
+ void (*destroy)(mutex_t *this);
+};
+
+/**
+ * Create a mutex instance.
+ *
+ * @param type type of mutex to create
+ * @return unlocked mutex instance
+ */
+mutex_t *mutex_create(mutex_type_t type);
+
+#endif /** THREADING_MUTEX_H_ @} */
+
diff --git a/src/libstrongswan/threading/rwlock.c b/src/libstrongswan/threading/rwlock.c
new file mode 100644
index 000000000..ee9fb10be
--- /dev/null
+++ b/src/libstrongswan/threading/rwlock.c
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2008-2009 Tobias Brunner
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#define _GNU_SOURCE
+#include <pthread.h>
+
+#include <library.h>
+#include <debug.h>
+
+#include "rwlock.h"
+#include "condvar.h"
+#include "mutex.h"
+#include "lock_profiler.h"
+
+typedef struct private_rwlock_t private_rwlock_t;
+
+/**
+ * private data of rwlock
+ */
+struct private_rwlock_t {
+
+ /**
+ * public functions
+ */
+ rwlock_t public;
+
+#ifdef HAVE_PTHREAD_RWLOCK_INIT
+
+ /**
+ * wrapped pthread rwlock
+ */
+ pthread_rwlock_t rwlock;
+
+#else
+
+ /**
+ * mutex to emulate a native rwlock
+ */
+ mutex_t *mutex;
+
+ /**
+ * condvar to handle writers
+ */
+ condvar_t *writers;
+
+ /**
+ * condvar to handle readers
+ */
+ condvar_t *readers;
+
+ /**
+ * number of waiting writers
+ */
+ u_int waiting_writers;
+
+ /**
+ * number of readers holding the lock
+ */
+ u_int reader_count;
+
+ /**
+ * current writer thread, if any
+ */
+ pthread_t writer;
+
+#endif /* HAVE_PTHREAD_RWLOCK_INIT */
+
+ /**
+ * profiling info, if enabled
+ */
+ lock_profile_t profile;
+};
+
+
+#ifdef HAVE_PTHREAD_RWLOCK_INIT
+
+/**
+ * Implementation of rwlock_t.read_lock
+ */
+static void read_lock(private_rwlock_t *this)
+{
+ int err;
+
+ profiler_start(&this->profile);
+ err = pthread_rwlock_rdlock(&this->rwlock);
+ if (err != 0)
+ {
+ DBG1("!!! RWLOCK READ LOCK ERROR: %s !!!", strerror(err));
+ }
+ profiler_end(&this->profile);
+}
+
+/**
+ * Implementation of rwlock_t.write_lock
+ */
+static void write_lock(private_rwlock_t *this)
+{
+ int err;
+
+ profiler_start(&this->profile);
+ err = pthread_rwlock_wrlock(&this->rwlock);
+ if (err != 0)
+ {
+ DBG1("!!! RWLOCK WRITE LOCK ERROR: %s !!!", strerror(err));
+ }
+ profiler_end(&this->profile);
+}
+
+/**
+ * Implementation of rwlock_t.try_write_lock
+ */
+static bool try_write_lock(private_rwlock_t *this)
+{
+ return pthread_rwlock_trywrlock(&this->rwlock) == 0;
+}
+
+/**
+ * Implementation of rwlock_t.unlock
+ */
+static void rw_unlock(private_rwlock_t *this)
+{
+ int err;
+
+ err = pthread_rwlock_unlock(&this->rwlock);
+ if (err != 0)
+ {
+ DBG1("!!! RWLOCK UNLOCK ERROR: %s !!!", strerror(err));
+ }
+}
+
+/**
+ * Implementation of rwlock_t.destroy
+ */
+static void rw_destroy(private_rwlock_t *this)
+{
+ pthread_rwlock_destroy(&this->rwlock);
+ profiler_cleanup(&this->profile);
+ free(this);
+}
+
+/*
+ * see header file
+ */
+rwlock_t *rwlock_create(rwlock_type_t type)
+{
+ switch (type)
+ {
+ case RWLOCK_TYPE_DEFAULT:
+ default:
+ {
+ private_rwlock_t *this = malloc_thing(private_rwlock_t);
+
+ this->public.read_lock = (void(*)(rwlock_t*))read_lock;
+ this->public.write_lock = (void(*)(rwlock_t*))write_lock;
+ this->public.try_write_lock = (bool(*)(rwlock_t*))try_write_lock;
+ this->public.unlock = (void(*)(rwlock_t*))rw_unlock;
+ this->public.destroy = (void(*)(rwlock_t*))rw_destroy;
+
+ pthread_rwlock_init(&this->rwlock, NULL);
+ profiler_init(&this->profile);
+
+ return &this->public;
+ }
+ }
+}
+
+#else /* HAVE_PTHREAD_RWLOCK_INIT */
+
+/**
+ * This implementation of the rwlock_t interface uses mutex_t and condvar_t
+ * primitives, if the pthread_rwlock_* group of functions is not available.
+ *
+ * The following constraints are enforced:
+ * - Multiple readers can hold the lock at the same time.
+ * - Only a single writer can hold the lock at any given time.
+ * - A writer must block until all readers have released the lock before
+ * obtaining the lock exclusively.
+ * - Readers that arrive while a writer is waiting to acquire the lock will
+ * block until after the writer has obtained and released the lock.
+ * These constraints allow for read sharing, prevent write sharing, prevent
+ * read-write sharing and prevent starvation of writers by a steady stream
+ * of incoming readers. Reader starvation is not prevented (this could happen
+ * if there are more writers than readers).
+ *
+ * The implementation does not support recursive locking and readers must not
+ * acquire the lock exclusively at the same time and vice-versa (this is not
+ * checked or enforced so behave yourself to prevent deadlocks).
+ */
+
+/**
+ * Implementation of rwlock_t.read_lock
+ */
+static void read_lock(private_rwlock_t *this)
+{
+ profiler_start(&this->profile);
+ this->mutex->lock(this->mutex);
+ while (this->writer || this->waiting_writers)
+ {
+ this->readers->wait(this->readers, this->mutex);
+ }
+ this->reader_count++;
+ profiler_end(&this->profile);
+ this->mutex->unlock(this->mutex);
+}
+
+/**
+ * Implementation of rwlock_t.write_lock
+ */
+static void write_lock(private_rwlock_t *this)
+{
+ profiler_start(&this->profile);
+ this->mutex->lock(this->mutex);
+ this->waiting_writers++;
+ while (this->writer || this->reader_count)
+ {
+ this->writers->wait(this->writers, this->mutex);
+ }
+ this->waiting_writers--;
+ this->writer = pthread_self();
+ profiler_end(&this->profile);
+ this->mutex->unlock(this->mutex);
+}
+
+/**
+ * Implementation of rwlock_t.try_write_lock
+ */
+static bool try_write_lock(private_rwlock_t *this)
+{
+ bool res = FALSE;
+ this->mutex->lock(this->mutex);
+ if (!this->writer && !this->reader_count)
+ {
+ res = TRUE;
+ this->writer = pthread_self();
+ }
+ this->mutex->unlock(this->mutex);
+ return res;
+}
+
+/**
+ * Implementation of rwlock_t.unlock
+ */
+static void rw_unlock(private_rwlock_t *this)
+{
+ this->mutex->lock(this->mutex);
+ if (this->writer == pthread_self())
+ {
+ this->writer = 0;
+ if (this->waiting_writers)
+ {
+ this->writers->signal(this->writers);
+ }
+ else
+ {
+ this->readers->broadcast(this->readers);
+ }
+ }
+ else
+ {
+ this->reader_count--;
+ if (!this->reader_count)
+ {
+ this->writers->signal(this->writers);
+ }
+ }
+ this->mutex->unlock(this->mutex);
+}
+
+/**
+ * Implementation of rwlock_t.destroy
+ */
+static void rw_destroy(private_rwlock_t *this)
+{
+ this->mutex->destroy(this->mutex);
+ this->writers->destroy(this->writers);
+ this->readers->destroy(this->readers);
+ profiler_cleanup(&this->profile);
+ free(this);
+}
+
+/*
+ * see header file
+ */
+rwlock_t *rwlock_create(rwlock_type_t type)
+{
+ switch (type)
+ {
+ case RWLOCK_TYPE_DEFAULT:
+ default:
+ {
+ private_rwlock_t *this = malloc_thing(private_rwlock_t);
+
+ this->public.read_lock = (void(*)(rwlock_t*))read_lock;
+ this->public.write_lock = (void(*)(rwlock_t*))write_lock;
+ this->public.try_write_lock = (bool(*)(rwlock_t*))try_write_lock;
+ this->public.unlock = (void(*)(rwlock_t*))rw_unlock;
+ this->public.destroy = (void(*)(rwlock_t*))rw_destroy;
+
+ this->mutex = mutex_create(MUTEX_TYPE_DEFAULT);
+ this->writers = condvar_create(CONDVAR_TYPE_DEFAULT);
+ this->readers = condvar_create(CONDVAR_TYPE_DEFAULT);
+ this->waiting_writers = 0;
+ this->reader_count = 0;
+ this->writer = 0;
+
+ profiler_init(&this->profile);
+
+ return &this->public;
+ }
+ }
+}
+
+#endif /* HAVE_PTHREAD_RWLOCK_INIT */
+
diff --git a/src/libstrongswan/threading/rwlock.h b/src/libstrongswan/threading/rwlock.h
new file mode 100644
index 000000000..a86a241c5
--- /dev/null
+++ b/src/libstrongswan/threading/rwlock.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2008-2009 Tobias Brunner
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup rwlock rwlock
+ * @{ @ingroup threading
+ */
+
+#ifndef THREADING_RWLOCK_H_
+#define THREADING_RWLOCK_H_
+
+typedef struct rwlock_t rwlock_t;
+typedef enum rwlock_type_t rwlock_type_t;
+
+/**
+ * Type of read-write lock.
+ */
+enum rwlock_type_t {
+ /** default condvar */
+ RWLOCK_TYPE_DEFAULT = 0,
+};
+
+/**
+ * Read-Write lock wrapper.
+ */
+struct rwlock_t {
+
+ /**
+ * Acquire the read lock.
+ */
+ void (*read_lock)(rwlock_t *this);
+
+ /**
+ * Acquire the write lock.
+ */
+ void (*write_lock)(rwlock_t *this);
+
+ /**
+ * Try to acquire the write lock.
+ *
+ * Never blocks, but returns FALSE if the lock was already occupied.
+ *
+ * @return TRUE if lock acquired
+ */
+ bool (*try_write_lock)(rwlock_t *this);
+
+ /**
+ * Release any acquired lock.
+ */
+ void (*unlock)(rwlock_t *this);
+
+ /**
+ * Destroy the read-write lock.
+ */
+ void (*destroy)(rwlock_t *this);
+};
+
+/**
+ * Create a read-write lock instance.
+ *
+ * @param type type of rwlock to create
+ * @return unlocked rwlock instance
+ */
+rwlock_t *rwlock_create(rwlock_type_t type);
+
+#endif /** THREADING_RWLOCK_H_ @} */
+
diff --git a/src/libstrongswan/threading/thread.c b/src/libstrongswan/threading/thread.c
new file mode 100644
index 000000000..bbfb2c2c6
--- /dev/null
+++ b/src/libstrongswan/threading/thread.c
@@ -0,0 +1,440 @@
+/*
+ * Copyright (C) 2009 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#define _GNU_SOURCE
+#include <pthread.h>
+#include <signal.h>
+#include <semaphore.h>
+
+#include <library.h>
+#include <debug.h>
+
+#include <threading/thread_value.h>
+#include <threading/mutex.h>
+#include <utils/linked_list.h>
+
+#include "thread.h"
+
+typedef struct private_thread_t private_thread_t;
+
+struct private_thread_t {
+ /**
+ * Public interface.
+ */
+ thread_t public;
+
+ /**
+ * Human-readable ID of this thread.
+ */
+ u_int id;
+
+ /**
+ * ID of the underlying thread.
+ */
+ pthread_t thread_id;
+
+ /**
+ * Main function of this thread (NULL for the main thread).
+ */
+ thread_main_t main;
+
+ /**
+ * Argument for the main function.
+ */
+ void *arg;
+
+ /**
+ * Stack of cleanup handlers.
+ */
+ linked_list_t *cleanup_handlers;
+
+ /**
+ * Mutex to make modifying thread properties safe.
+ */
+ mutex_t *mutex;
+
+ /**
+ * Semaphore used to sync the creation/start of the thread.
+ */
+ sem_t created;
+
+ /**
+ * TRUE if this thread has been detached or joined, i.e. can be cleaned
+ * up after terminating.
+ */
+ bool detached_or_joined;
+
+ /**
+ * TRUE if the threads has terminated (cancelled, via thread_exit or
+ * returned from the main function)
+ */
+ bool terminated;
+
+};
+
+typedef struct {
+ /**
+ * Cleanup callback function.
+ */
+ thread_cleanup_t cleanup;
+
+ /**
+ * Argument provided to the cleanup function.
+ */
+ void *arg;
+
+} cleanup_handler_t;
+
+
+/**
+ * Next thread ID.
+ */
+static u_int next_id = 1;
+
+/**
+ * Mutex to safely access the next thread ID.
+ */
+static mutex_t *id_mutex;
+
+/**
+ * Store the thread object in a thread-specific value.
+ */
+static thread_value_t *current_thread;
+
+#ifndef HAVE_PTHREAD_CANCEL
+/* if pthread_cancel is not available, we emulate it using a signal */
+#define SIG_CANCEL (SIGRTMIN+7)
+
+/* the signal handler for SIG_CANCEL uses pthread_exit to terminate the
+ * "cancelled" thread */
+static void cancel_signal_handler(int sig)
+{
+ pthread_exit(NULL);
+}
+#endif
+
+
+/**
+ * Destroy an internal thread object.
+ *
+ * @note The mutex of this thread object has to be locked, it gets unlocked
+ * automatically.
+ */
+static void thread_destroy(private_thread_t *this)
+{
+ if (!this->terminated || !this->detached_or_joined)
+ {
+ this->mutex->unlock(this->mutex);
+ return;
+ }
+ this->cleanup_handlers->destroy(this->cleanup_handlers);
+ this->mutex->unlock(this->mutex);
+ this->mutex->destroy(this->mutex);
+ sem_destroy(&this->created);
+ free(this);
+}
+
+/**
+ * Implementation of thread_t.cancel.
+ */
+static void cancel(private_thread_t *this)
+{
+ this->mutex->lock(this->mutex);
+ if (pthread_equal(this->thread_id, pthread_self()))
+ {
+ this->mutex->unlock(this->mutex);
+ DBG1("!!! CANNOT CANCEL CURRENT THREAD !!!");
+ return;
+ }
+#ifdef HAVE_PTHREAD_CANCEL
+ pthread_cancel(this->thread_id);
+#else
+ pthread_kill(this->thread_id, SIG_CANCEL);
+#endif /* HAVE_PTHREAD_CANCEL */
+ this->mutex->unlock(this->mutex);
+}
+
+/**
+ * Implementation of thread_t.kill.
+ */
+static void _kill(private_thread_t *this, int sig)
+{
+ this->mutex->lock(this->mutex);
+ if (pthread_equal(this->thread_id, pthread_self()))
+ {
+ /* it might actually be possible to send a signal to pthread_self (there
+ * is an example in raise(3) describing that), the problem is though,
+ * that the thread only returns here after the signal handler has
+ * returned, so depending on the signal, the lock might not get
+ * unlocked. */
+ this->mutex->unlock(this->mutex);
+ DBG1("!!! CANNOT SEND SIGNAL TO CURRENT THREAD !!!");
+ return;
+ }
+ pthread_kill(this->thread_id, sig);
+ this->mutex->unlock(this->mutex);
+}
+
+/**
+ * Implementation of thread_t.detach.
+ */
+static void detach(private_thread_t *this)
+{
+ this->mutex->lock(this->mutex);
+ pthread_detach(this->thread_id);
+ this->detached_or_joined = TRUE;
+ thread_destroy(this);
+}
+
+/**
+ * Implementation of thread_t.join.
+ */
+static void *join(private_thread_t *this)
+{
+ pthread_t thread_id;
+ void *val;
+ this->mutex->lock(this->mutex);
+ if (pthread_equal(this->thread_id, pthread_self()))
+ {
+ this->mutex->unlock(this->mutex);
+ DBG1("!!! CANNOT JOIN CURRENT THREAD !!!");
+ return NULL;
+ }
+ if (this->detached_or_joined)
+ {
+ this->mutex->unlock(this->mutex);
+ DBG1("!!! CANNOT JOIN DETACHED THREAD !!!");
+ return NULL;
+ }
+ thread_id = this->thread_id;
+ this->detached_or_joined = TRUE;
+ if (this->terminated)
+ {
+ /* thread has terminated before the call to join */
+ thread_destroy(this);
+ }
+ else
+ {
+ /* thread_destroy is called when the thread terminates normally */
+ this->mutex->unlock(this->mutex);
+ }
+ pthread_join(thread_id, &val);
+ return val;
+}
+
+/**
+ * Create an internal thread object.
+ */
+static private_thread_t *thread_create_internal()
+{
+ private_thread_t *this = malloc_thing(private_thread_t);
+ this->public.cancel = (void(*)(thread_t*))cancel;
+ this->public.kill = (void(*)(thread_t*,int))_kill;
+ this->public.detach = (void(*)(thread_t*))detach;
+ this->public.join = (void*(*)(thread_t*))join;
+
+ this->id = 0;
+ this->thread_id = 0;
+ this->main = NULL;
+ this->arg = NULL;
+ this->cleanup_handlers = linked_list_create();
+ this->mutex = mutex_create(MUTEX_TYPE_DEFAULT);
+ sem_init(&this->created, FALSE, 0);
+ this->detached_or_joined = FALSE;
+ this->terminated = FALSE;
+
+ return this;
+}
+
+/**
+ * Main cleanup function for threads.
+ */
+static void thread_cleanup(private_thread_t *this)
+{
+ cleanup_handler_t *handler;
+ this->mutex->lock(this->mutex);
+ while (this->cleanup_handlers->remove_last(this->cleanup_handlers,
+ (void**)&handler) == SUCCESS)
+ {
+ handler->cleanup(handler->arg);
+ free(handler);
+ }
+ this->terminated = TRUE;
+ thread_destroy(this);
+}
+
+/**
+ * Main function wrapper for threads.
+ */
+static void *thread_main(private_thread_t *this)
+{
+ void *res;
+ sem_wait(&this->created);
+ current_thread->set(current_thread, this);
+ pthread_cleanup_push((thread_cleanup_t)thread_cleanup, this);
+ res = this->main(this->arg);
+ pthread_cleanup_pop(TRUE);
+ return res;
+}
+
+/**
+ * Described in header.
+ */
+thread_t *thread_create(thread_main_t main, void *arg)
+{
+ private_thread_t *this = thread_create_internal();
+ this->main = main;
+ this->arg = arg;
+ if (pthread_create(&this->thread_id, NULL, (void*)thread_main, this) != 0)
+ {
+ DBG1("failed to create thread!");
+ thread_destroy(this);
+ return NULL;
+ }
+ id_mutex->lock(id_mutex);
+ this->id = next_id++;
+ id_mutex->unlock(id_mutex);
+ sem_post(&this->created);
+ return &this->public;
+}
+
+/**
+ * Described in header.
+ */
+thread_t *thread_current()
+{
+ return current_thread->get(current_thread);
+}
+
+/**
+ * Described in header.
+ */
+u_int thread_current_id()
+{
+ private_thread_t *this = (private_thread_t*)thread_current();
+ return this->id;
+}
+
+/**
+ * Described in header.
+ */
+void thread_cleanup_push(thread_cleanup_t cleanup, void *arg)
+{
+ private_thread_t *this = (private_thread_t*)thread_current();
+ cleanup_handler_t *handler;
+ this->mutex->lock(this->mutex);
+ handler = malloc_thing(cleanup_handler_t);
+ handler->cleanup = cleanup;
+ handler->arg = arg;
+ this->cleanup_handlers->insert_last(this->cleanup_handlers, handler);
+ this->mutex->unlock(this->mutex);
+}
+
+/**
+ * Described in header.
+ */
+void thread_cleanup_pop(bool execute)
+{
+ private_thread_t *this = (private_thread_t*)thread_current();
+ cleanup_handler_t *handler;
+ this->mutex->lock(this->mutex);
+ if (this->cleanup_handlers->remove_last(this->cleanup_handlers,
+ (void**)&handler) != SUCCESS)
+ {
+ this->mutex->unlock(this->mutex);
+ DBG1("!!! THREAD CLEANUP ERROR !!!");
+ return;
+ }
+ this->mutex->unlock(this->mutex);
+
+ if (execute)
+ {
+ handler->cleanup(handler->arg);
+ }
+ free(handler);
+}
+
+/**
+ * Described in header.
+ */
+bool thread_cancelability(bool enable)
+{
+#ifdef HAVE_PTHREAD_CANCEL
+ int old;
+ pthread_setcancelstate(enable ? PTHREAD_CANCEL_ENABLE
+ : PTHREAD_CANCEL_DISABLE, &old);
+ return old == PTHREAD_CANCEL_ENABLE;
+#else
+ sigset_t new, old;
+ sigemptyset(&new);
+ sigaddset(&new, SIG_CANCEL);
+ pthread_sigmask(enable ? SIG_UNBLOCK : SIG_BLOCK, &new, &old);
+ return sigismember(&old, SIG_CANCEL) == 0;
+#endif /* HAVE_PTHREAD_CANCEL */
+}
+
+/**
+ * Described in header.
+ */
+void thread_cancellation_point()
+{
+ bool old = thread_cancelability(TRUE);
+#ifdef HAVE_PTHREAD_CANCEL
+ pthread_testcancel();
+#endif /* HAVE_PTHREAD_CANCEL */
+ thread_cancelability(old);
+}
+
+/**
+ * Described in header.
+ */
+void thread_exit(void *val)
+{
+ pthread_exit(val);
+}
+
+/**
+ * Described in header.
+ */
+void threads_init()
+{
+ private_thread_t *main_thread = thread_create_internal();
+ main_thread->id = 0;
+ main_thread->thread_id = pthread_self();
+ current_thread = thread_value_create(NULL);
+ current_thread->set(current_thread, (void*)main_thread);
+ id_mutex = mutex_create(MUTEX_TYPE_DEFAULT);
+
+#ifndef HAVE_PTHREAD_CANCEL
+ { /* install a signal handler for our custom SIG_CANCEL */
+ struct sigaction action = {
+ .sa_handler = cancel_signal_handler
+ };
+ sigaction(SIG_CANCEL, &action, NULL);
+ }
+#endif /* HAVE_PTHREAD_CANCEL */
+}
+
+/**
+ * Described in header.
+ */
+void threads_deinit()
+{
+ private_thread_t *main_thread = (private_thread_t*)thread_current();
+ thread_destroy(main_thread);
+ current_thread->destroy(current_thread);
+ id_mutex->destroy(id_mutex);
+}
+
diff --git a/src/libstrongswan/threading/thread.h b/src/libstrongswan/threading/thread.h
new file mode 100644
index 000000000..6bf8fac79
--- /dev/null
+++ b/src/libstrongswan/threading/thread.h
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2009 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup thread thread
+ * @{ @ingroup threading
+ */
+
+#ifndef THREADING_THREAD_H_
+#define THREADING_THREAD_H_
+
+typedef struct thread_t thread_t;
+
+#ifdef __APPLE__
+/* on Mac OS X 10.5 several system calls we use are no cancellation points.
+ * fortunately, select isn't one of them, so we wrap some of the others with
+ * calls to select(2).
+ */
+#include <sys/socket.h>
+#include <sys/select.h>
+
+#define WRAP_WITH_SELECT(func, socket, ...)\
+ fd_set rfds; FD_ZERO(&rfds); FD_SET(socket, &rfds);\
+ if (select(socket + 1, &rfds, NULL, NULL, NULL) <= 0) { return -1; }\
+ return func(socket, __VA_ARGS__)
+
+static inline int cancellable_accept(int socket, struct sockaddr *address,
+ socklen_t *address_len)
+{
+ WRAP_WITH_SELECT(accept, socket, address, address_len);
+}
+#define accept cancellable_accept
+static inline int cancellable_recvfrom(int socket, void *buffer, size_t length,
+ int flags, struct sockaddr *address, socklen_t *address_len)
+{
+ WRAP_WITH_SELECT(recvfrom, socket, buffer, length, flags, address, address_len);
+}
+#define recvfrom cancellable_recvfrom
+#endif /* __APPLE__ */
+
+/**
+ * Main function of a thread.
+ *
+ * @param arg argument provided to constructor
+ * @return value provided to threads joining the terminating thread
+ */
+typedef void *(*thread_main_t)(void *arg);
+
+/**
+ * Cleanup callback function for a thread.
+ *
+ * @param arg argument provided to thread_cleanup_push
+ */
+typedef void (*thread_cleanup_t)(void *arg);
+
+
+/**
+ * Thread wrapper implements simple, portable and advanced thread functions.
+ *
+ * @note All threads other than the main thread need either to be joined or
+ * detached by calling the corresponding method.
+ */
+struct thread_t {
+
+ /**
+ * Cancel this thread.
+ */
+ void (*cancel)(thread_t *this);
+
+ /**
+ * Send a signal to this thread.
+ *
+ * @param sig the signal to be sent to this thread
+ */
+ void (*kill)(thread_t *this, int sig);
+
+ /**
+ * Detach this thread, this automatically destroys the thread object after
+ * the thread returned from its main function.
+ *
+ * @note Calling detach is like calling destroy on other objects.
+ */
+ void (*detach)(thread_t *this);
+
+ /**
+ * Join this thread, this automatically destroys the thread object
+ * afterwards.
+ *
+ * @note Calling join is like calling destroy on other objects.
+ *
+ * @return the value returned from the thread's main function or
+ * a call to exit.
+ */
+ void *(*join)(thread_t *this);
+
+};
+
+
+/**
+ * Create a new thread instance.
+ *
+ * @param main thread main function
+ * @param arg argument provided to the main function
+ * @return thread instance
+ */
+thread_t *thread_create(thread_main_t main, void *arg);
+
+/**
+ * Get a thread object for the current thread.
+ *
+ * @return thread instance
+ */
+thread_t *thread_current();
+
+/**
+ * Get the human-readable ID of the current thread.
+ *
+ * The IDs are assigned incrementally starting from 1.
+ *
+ * @return human-readable ID
+ */
+u_int thread_current_id();
+
+/**
+ * Push a function onto the current thread's cleanup handler stack.
+ * The callback function is called whenever the thread is cancelled, exits or
+ * thread_cleanup_pop is called with TRUE as execute argument.
+ *
+ * @param cleanup function called on thread exit
+ * @param arg argument provided to the callback
+ */
+void thread_cleanup_push(thread_cleanup_t cleanup, void *arg);
+
+/**
+ * Remove the top function from the current thread's cleanup handler stack
+ * and optionally execute it.
+ *
+ * @param execute TRUE to execute the function
+ */
+void thread_cleanup_pop(bool execute);
+
+/**
+ * Enable or disable the cancelability of the current thread. The current
+ * value is returned.
+ *
+ * @param enable TRUE to enable cancelability
+ * @return the current state of the cancelability
+ */
+bool thread_cancelability(bool enable);
+
+/**
+ * Force creation of a cancellation point in the calling thread.
+ */
+void thread_cancellation_point();
+
+/**
+ * Exit the current thread.
+ *
+ * @param val value provided to threads joining the current thread
+ */
+void thread_exit(void *val);
+
+/**
+ * Called by the main thread to initialize the thread management.
+ */
+void threads_init();
+
+/**
+ * Called by the main thread to deinitialize the thread management.
+ */
+void threads_deinit();
+
+
+#endif /** THREADING_THREAD_H_ @} */
+
diff --git a/src/libstrongswan/threading/thread_value.c b/src/libstrongswan/threading/thread_value.c
new file mode 100644
index 000000000..8f2a8846c
--- /dev/null
+++ b/src/libstrongswan/threading/thread_value.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2009 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#define _GNU_SOURCE
+#include <pthread.h>
+
+#include <library.h>
+
+#include "thread_value.h"
+
+typedef struct private_thread_value_t private_thread_value_t;
+
+struct private_thread_value_t {
+ /**
+ * Public interface.
+ */
+ thread_value_t public;
+
+ /**
+ * Key to access thread-specific values.
+ */
+ pthread_key_t key;
+
+};
+
+
+/**
+ * Implementation of thread_value_t.set.
+ */
+static void set(private_thread_value_t *this, void *val)
+{
+ pthread_setspecific(this->key, val);
+}
+
+/**
+ * Implementation of thread_value_t.get.
+ */
+static void *get(private_thread_value_t *this)
+{
+ return pthread_getspecific(this->key);
+}
+
+/**
+ * Implementation of thread_value_t.destroy.
+ */
+static void destroy(private_thread_value_t *this)
+{
+ pthread_key_delete(this->key);
+ free(this);
+}
+
+
+/**
+ * Described in header.
+ */
+thread_value_t *thread_value_create(thread_cleanup_t destructor)
+{
+ private_thread_value_t *this = malloc_thing(private_thread_value_t);
+ this->public.set = (void(*)(thread_value_t*,void*))set;
+ this->public.get = (void*(*)(thread_value_t*))get;
+ this->public.destroy = (void(*)(thread_value_t*))destroy;
+
+ pthread_key_create(&this->key, destructor);
+ return &this->public;
+}
+
diff --git a/src/libstrongswan/threading/thread_value.h b/src/libstrongswan/threading/thread_value.h
new file mode 100644
index 000000000..48f5f7d6b
--- /dev/null
+++ b/src/libstrongswan/threading/thread_value.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2009 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup thread_value thread_value
+ * @{ @ingroup threading
+ */
+
+#ifndef THREADING_THREAD_VALUE_H_
+#define THREADING_THREAD_VALUE_H_
+
+#include <threading/thread.h>
+
+typedef struct thread_value_t thread_value_t;
+
+/**
+ * Wrapper for thread-specific values.
+ */
+struct thread_value_t {
+
+ /**
+ * Set a thread-specific value.
+ *
+ * @param val thread specific value
+ */
+ void (*set)(thread_value_t *this, void *val);
+
+ /**
+ * Get a thread-specific value.
+ *
+ * @return the value specific to the current thread
+ */
+ void *(*get)(thread_value_t *this);
+
+ /**
+ * Destroys this thread specific value wrapper. There is no check for
+ * non-NULL values which are currently assigned to the calling thread, no
+ * destructor is called.
+ */
+ void (*destroy)(thread_value_t *this);
+
+};
+
+/**
+ * Create a new thread-specific value wrapper.
+ *
+ * The optional destructor is called whenever a thread terminates, with the
+ * assigned value as argument. It is not called if that value is NULL.
+ *
+ * @param destructor destructor
+ * @return thread-specific value wrapper
+ */
+thread_value_t *thread_value_create(thread_cleanup_t destructor);
+
+#endif /** THREADING_THREAD_VALUE_H_ @} */
+