/*
- * Copyright (C) 2008-2009 Tobias Brunner
+ * Copyright (C) 2008-2012 Tobias Brunner
* Copyright (C) 2008 Martin Willi
- * Hochschule fuer Technik Rapperswil
+ * HSR 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
#include <errno.h>
#include <library.h>
-#include <debug.h>
+#include <utils/debug.h>
+#include "thread.h"
+#include "condvar.h"
#include "mutex.h"
#include "lock_profiler.h"
pthread_mutex_t mutex;
/**
- * is this a recursiv emutex, implementing private_r_mutex_t?
+ * is this a recursive mutex, implementing private_r_mutex_t?
*/
bool recursive;
/**
* thread which currently owns mutex
*/
- pthread_t thread;
+ thread_t *thread;
/**
- * times we have locked the lock, stored per thread
+ * times the current thread locked the mutex
*/
- pthread_key_t times;
+ u_int times;
};
/**
};
-
-/**
- * Implementation of mutex_t.lock.
- */
-static void lock(private_mutex_t *this)
+METHOD(mutex_t, lock, void,
+ private_mutex_t *this)
{
int err;
err = pthread_mutex_lock(&this->mutex);
if (err)
{
- DBG1("!!! MUTEX LOCK ERROR: %s !!!", strerror(err));
+ DBG1(DBG_LIB, "!!! MUTEX LOCK ERROR: %s !!!", strerror(err));
}
profiler_end(&this->profile);
}
-/**
- * Implementation of mutex_t.unlock.
- */
-static void unlock(private_mutex_t *this)
+METHOD(mutex_t, unlock, void,
+ private_mutex_t *this)
{
int err;
err = pthread_mutex_unlock(&this->mutex);
if (err)
{
- DBG1("!!! MUTEX UNLOCK ERROR: %s !!!", strerror(err));
+ DBG1(DBG_LIB, "!!! MUTEX UNLOCK ERROR: %s !!!", strerror(err));
}
}
-/**
- * Implementation of mutex_t.lock.
- */
-static void lock_r(private_r_mutex_t *this)
+METHOD(mutex_t, lock_r, void,
+ private_r_mutex_t *this)
{
- pthread_t self = pthread_self();
+ thread_t *self = thread_current();
- if (this->thread == self)
+ if (cas_ptr(&this->thread, self, self))
{
- uintptr_t times;
-
- /* times++ */
- times = (uintptr_t)pthread_getspecific(this->times);
- pthread_setspecific(this->times, (void*)times + 1);
+ this->times++;
}
else
{
lock(&this->generic);
- this->thread = self;
- /* times = 1 */
- pthread_setspecific(this->times, (void*)1);
+ cas_ptr(&this->thread, NULL, self);
+ this->times = 1;
}
}
-/**
- * Implementation of mutex_t.unlock.
- */
-static void unlock_r(private_r_mutex_t *this)
+METHOD(mutex_t, unlock_r, void,
+ 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)
+ if (--this->times == 0)
{
- this->thread = 0;
+ cas_ptr(&this->thread, thread_current(), NULL);
unlock(&this->generic);
}
}
-/**
- * Implementation of mutex_t.destroy
- */
-static void mutex_destroy(private_mutex_t *this)
+METHOD(mutex_t, mutex_destroy, void,
+ 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)
+METHOD(mutex_t, mutex_destroy_r, void,
+ private_r_mutex_t *this)
{
profiler_cleanup(&this->generic.profile);
pthread_mutex_destroy(&this->generic.mutex);
- pthread_key_delete(this->times);
free(this);
}
{
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;
+ private_r_mutex_t *this;
+
+ INIT(this,
+ .generic = {
+ .public = {
+ .lock = _lock_r,
+ .unlock = _unlock_r,
+ .destroy = _mutex_destroy_r,
+ },
+ .recursive = TRUE,
+ },
+ );
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);
+ private_mutex_t *this;
- this->public.lock = (void(*)(mutex_t*))lock;
- this->public.unlock = (void(*)(mutex_t*))unlock;
- this->public.destroy = (void(*)(mutex_t*))mutex_destroy;
+ INIT(this,
+ .public = {
+ .lock = _lock,
+ .unlock = _unlock,
+ .destroy = _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)
+METHOD(condvar_t, wait_, void,
+ private_condvar_t *this, private_mutex_t *mutex)
{
if (mutex->recursive)
{
private_r_mutex_t* recursive = (private_r_mutex_t*)mutex;
+ thread_t *self = thread_current();
+ u_int times;
+ /* keep track of the number of times this thread locked the mutex */
+ times = recursive->times;
/* mutex owner gets cleared during condvar wait */
- recursive->thread = 0;
+ cas_ptr(&recursive->thread, self, NULL);
pthread_cond_wait(&this->condvar, &mutex->mutex);
- recursive->thread = pthread_self();
+ cas_ptr(&recursive->thread, NULL, self);
+ recursive->times = times;
}
else
{
}
}
-/**
- * Implementation of condvar_t.timed_wait_abs.
- */
-static bool timed_wait_abs(private_condvar_t *this, private_mutex_t *mutex,
- timeval_t time)
+/* use the monotonic clock based version of this function if available */
+#if defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC) && \
+ !defined(HAVE_CONDATTR_CLOCK_MONOTONIC)
+#define pthread_cond_timedwait pthread_cond_timedwait_monotonic
+#endif
+
+METHOD(condvar_t, timed_wait_abs, bool,
+ private_condvar_t *this, private_mutex_t *mutex, timeval_t time)
{
struct timespec ts;
bool timed_out;
if (mutex->recursive)
{
private_r_mutex_t* recursive = (private_r_mutex_t*)mutex;
+ thread_t *self = thread_current();
+ u_int times;
- recursive->thread = 0;
+ times = recursive->times;
+ cas_ptr(&recursive->thread, self, NULL);
timed_out = pthread_cond_timedwait(&this->condvar, &mutex->mutex,
&ts) == ETIMEDOUT;
- recursive->thread = pthread_self();
+ cas_ptr(&recursive->thread, NULL, self);
+ recursive->times = times;
}
else
{
return timed_out;
}
-/**
- * Implementation of condvar_t.timed_wait.
- */
-static bool timed_wait(private_condvar_t *this, private_mutex_t *mutex,
- u_int timeout)
+METHOD(condvar_t, timed_wait, bool,
+ private_condvar_t *this, private_mutex_t *mutex, u_int timeout)
{
timeval_t tv;
u_int s, ms;
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++;
- }
+ timeval_add_ms(&tv, ms);
return timed_wait_abs(this, mutex, tv);
}
-/**
- * Implementation of condvar_t.signal.
- */
-static void _signal(private_condvar_t *this)
+METHOD(condvar_t, signal_, void,
+ private_condvar_t *this)
{
pthread_cond_signal(&this->condvar);
}
-/**
- * Implementation of condvar_t.broadcast.
- */
-static void broadcast(private_condvar_t *this)
+METHOD(condvar_t, broadcast, void,
+ private_condvar_t *this)
{
pthread_cond_broadcast(&this->condvar);
}
-/**
- * Implementation of condvar_t.destroy
- */
-static void condvar_destroy(private_condvar_t *this)
+METHOD(condvar_t, condvar_destroy, void,
+ private_condvar_t *this)
{
pthread_cond_destroy(&this->condvar);
free(this);
case CONDVAR_TYPE_DEFAULT:
default:
{
- pthread_condattr_t condattr;
- 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;
-
- pthread_condattr_init(&condattr);
+ private_condvar_t *this;
+
+ INIT(this,
+ .public = {
+ .wait = (void*)_wait_,
+ .timed_wait = (void*)_timed_wait,
+ .timed_wait_abs = (void*)_timed_wait_abs,
+ .signal = _signal_,
+ .broadcast = _broadcast,
+ .destroy = _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);
+ pthread_condattr_setclock(&condattr, TIME_CLOCK_ID);
+#endif
+ pthread_cond_init(&this->condvar, &condattr);
+ pthread_condattr_destroy(&condattr);
+ }
#endif
- pthread_cond_init(&this->condvar, &condattr);
- pthread_condattr_destroy(&condattr);
return &this->public;
}