]> git.ipfire.org Git - thirdparty/strongswan.git/blobdiff - src/libstrongswan/threading/mutex.c
time: Allow using different clocks
[thirdparty/strongswan.git] / src / libstrongswan / threading / mutex.c
index d05b8674ec6634eac740ccc5c4f3c600dd9023e1..888f11df0797879b4033fd426b11442e97e0277c 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * 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"
 
@@ -46,7 +48,7 @@ struct private_mutex_t {
        pthread_mutex_t mutex;
 
        /**
-        * is this a recursiv emutex, implementing private_r_mutex_t?
+        * is this a recursivmutex, implementing private_r_mutex_t?
         */
        bool recursive;
 
@@ -69,12 +71,12 @@ struct private_r_mutex_t {
        /**
         * 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;
 };
 
 /**
@@ -95,11 +97,8 @@ struct private_condvar_t {
 };
 
 
-
-/**
- * Implementation of mutex_t.lock.
- */
-static void lock(private_mutex_t *this)
+METHOD(mutex_t, lock, void,
+       private_mutex_t *this)
 {
        int err;
 
@@ -107,85 +106,63 @@ static void lock(private_mutex_t *this)
        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);
 }
 
@@ -198,31 +175,38 @@ mutex_t *mutex_create(mutex_type_t 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;
+                       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;
@@ -231,20 +215,22 @@ mutex_t *mutex_create(mutex_type_t type)
 }
 
 
-
-/**
- * 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
        {
@@ -252,11 +238,14 @@ static void _wait(private_condvar_t *this, private_mutex_t *mutex)
        }
 }
 
-/**
- * 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;
@@ -267,11 +256,15 @@ static bool timed_wait_abs(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;
 
-               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
        {
@@ -281,11 +274,8 @@ static bool timed_wait_abs(private_condvar_t *this, private_mutex_t *mutex,
        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;
@@ -296,36 +286,24 @@ static bool timed_wait(private_condvar_t *this, private_mutex_t *mutex,
        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);
@@ -341,22 +319,30 @@ condvar_t *condvar_create(condvar_type_t type)
                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;
                }