/*
- * Copyright (C) 2009 Tobias Brunner
+ * Copyright (C) 2009-2012 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
#define _GNU_SOURCE
#include <pthread.h>
#include <signal.h>
-#include <semaphore.h>
+
+#ifdef HAVE_GETTID
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_SYS_GETTID
+#include <sys/syscall.h>
+static inline pid_t gettid()
+{
+ return syscall(SYS_gettid);
+}
+#endif
#include <library.h>
-#include <debug.h>
+#include <utils/debug.h>
#include <threading/thread_value.h>
#include <threading/mutex.h>
-#include <utils/linked_list.h>
+#include <collections/linked_list.h>
#include "thread.h"
*/
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.
/**
* Next thread ID.
*/
-static u_int next_id = 1;
+static u_int next_id;
/**
* Mutex to safely access the next thread ID.
*/
static thread_value_t *current_thread;
+
#ifndef HAVE_PTHREAD_CANCEL
/* if pthread_cancel is not available, we emulate it using a signal */
+#ifdef ANDROID
+#define SIG_CANCEL SIGUSR2
+#else
#define SIG_CANCEL (SIGRTMIN+7)
+#endif
/* the signal handler for SIG_CANCEL uses pthread_exit to terminate the
* "cancelled" thread */
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)
+METHOD(thread_t, cancel, void,
+ private_thread_t *this)
{
this->mutex->lock(this->mutex);
if (pthread_equal(this->thread_id, pthread_self()))
this->mutex->unlock(this->mutex);
}
-/**
- * Implementation of thread_t.kill.
- */
-static void _kill(private_thread_t *this, int sig)
+METHOD(thread_t, kill_, void,
+ private_thread_t *this, int sig)
{
this->mutex->lock(this->mutex);
if (pthread_equal(this->thread_id, pthread_self()))
this->mutex->unlock(this->mutex);
}
-/**
- * Implementation of thread_t.detach.
- */
-static void detach(private_thread_t *this)
+METHOD(thread_t, detach, void,
+ private_thread_t *this)
{
this->mutex->lock(this->mutex);
pthread_detach(this->thread_id);
thread_destroy(this);
}
-/**
- * Implementation of thread_t.join.
- */
-static void *join(private_thread_t *this)
+METHOD(thread_t, join, void*,
+ 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);
}
pthread_join(thread_id, &val);
+
return val;
}
*/
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;
+ private_thread_t *this;
+
+ INIT(this,
+ .public = {
+ .cancel = _cancel,
+ .kill = _kill_,
+ .detach = _detach,
+ .join = _join,
+ },
+ .cleanup_handlers = linked_list_create(),
+ .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+ );
return this;
}
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);
+
+ /* TODO: this is not 100% portable as pthread_t is an opaque type (i.e.
+ * could be of any size, or even a struct) */
+#ifdef HAVE_GETTID
+ DBG2(DBG_LIB, "created thread %.2d [%u]",
+ this->id, gettid());
+#elif defined(WIN32)
+ DBG2(DBG_LIB, "created thread %.2d [%p]",
+ this->id, this->thread_id.p);
+#else
+ DBG2(DBG_LIB, "created thread %.2d [%lx]",
+ this->id, (u_long)this->thread_id);
+#endif
+
res = this->main(this->arg);
pthread_cleanup_pop(TRUE);
+
return res;
}
thread_t *thread_create(thread_main_t main, void *arg)
{
private_thread_t *this = thread_create_internal();
+
this->main = main;
this->arg = arg;
+ id_mutex->lock(id_mutex);
+ this->id = next_id++;
+ id_mutex->unlock(id_mutex);
+
if (pthread_create(&this->thread_id, NULL, (void*)thread_main, this) != 0)
{
DBG1(DBG_LIB, "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;
}
*/
thread_t *thread_current()
{
- return current_thread->get(current_thread);
+ private_thread_t *this;
+
+ this = (private_thread_t*)current_thread->get(current_thread);
+ if (!this)
+ {
+ this = thread_create_internal();
+
+ id_mutex->lock(id_mutex);
+ this->id = next_id++;
+ id_mutex->unlock(id_mutex);
+
+ current_thread->set(current_thread, (void*)this);
+ }
+ return &this->public;
}
/**
u_int thread_current_id()
{
private_thread_t *this = (private_thread_t*)thread_current();
- return this->id;
+
+ return this ? this->id : 0;
}
/**
{
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;
+
+ INIT(handler,
+ .cleanup = cleanup,
+ .arg = arg,
+ );
+
this->cleanup_handlers->insert_last(this->cleanup_handlers, handler);
- this->mutex->unlock(this->mutex);
}
/**
{
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(DBG_LIB, "!!! THREAD CLEANUP ERROR !!!");
return;
}
- this->mutex->unlock(this->mutex);
if (execute)
{
free(handler);
}
+/**
+ * Described in header.
+ */
+void thread_cleanup_popall()
+{
+ private_thread_t *this = (private_thread_t*)thread_current();
+ cleanup_handler_t *handler;
+
+ while (this->cleanup_handlers->get_count(this->cleanup_handlers))
+ {
+ this->cleanup_handlers->remove_last(this->cleanup_handlers,
+ (void**)&handler);
+ handler->cleanup(handler->arg);
+ free(handler);
+ }
+}
+
/**
* Described in header.
*/
{
#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 */
}
void thread_cancellation_point()
{
bool old = thread_cancelability(TRUE);
+
#ifdef HAVE_PTHREAD_CANCEL
pthread_testcancel();
#endif /* HAVE_PTHREAD_CANCEL */
pthread_exit(val);
}
+/**
+ * A dummy thread value that reserved pthread_key_t value "0". A buggy PKCS#11
+ * library mangles this key, without owning it, so we allocate it for them.
+ */
+static thread_value_t *dummy1;
+
/**
* Described in header.
*/
void threads_init()
{
private_thread_t *main_thread = thread_create_internal();
+
+ dummy1 = thread_value_create(NULL);
+
+ next_id = 1;
main_thread->id = 0;
main_thread->thread_id = pthread_self();
current_thread = thread_value_create(NULL);
void threads_deinit()
{
private_thread_t *main_thread = (private_thread_t*)thread_current();
+
+ dummy1->destroy(dummy1);
+
main_thread->mutex->lock(main_thread->mutex);
+ main_thread->terminated = TRUE;
+ main_thread->detached_or_joined = TRUE;
thread_destroy(main_thread);
current_thread->destroy(current_thread);
id_mutex->destroy(id_mutex);
}
-