mutex: Use atomics to set current thread in recursive mutex

Because this->thread is also read by threads that don't hold the
mutex the previous implementation was problematic (especially since
pthread_t is an opaque type of unknown length).

Fixes #654.
This commit is contained in:
Tobias Brunner 2014-07-17 10:35:42 +02:00
parent 7e433456fc
commit dbd7f4be31

View File

@ -23,6 +23,7 @@
#include <library.h> #include <library.h>
#include <utils/debug.h> #include <utils/debug.h>
#include "thread.h"
#include "condvar.h" #include "condvar.h"
#include "mutex.h" #include "mutex.h"
#include "lock_profiler.h" #include "lock_profiler.h"
@ -70,7 +71,7 @@ struct private_r_mutex_t {
/** /**
* thread which currently owns mutex * thread which currently owns mutex
*/ */
pthread_t thread; thread_t *thread;
/** /**
* times the current thread locked the mutex * times the current thread locked the mutex
@ -125,16 +126,16 @@ METHOD(mutex_t, unlock, void,
METHOD(mutex_t, lock_r, void, METHOD(mutex_t, lock_r, void,
private_r_mutex_t *this) private_r_mutex_t *this)
{ {
pthread_t self = pthread_self(); thread_t *self = thread_current();
if (pthread_equal(this->thread, self)) if (cas_ptr(&this->thread, self, self))
{ {
this->times++; this->times++;
} }
else else
{ {
lock(&this->generic); lock(&this->generic);
this->thread = self; cas_ptr(&this->thread, NULL, self);
this->times = 1; this->times = 1;
} }
} }
@ -144,7 +145,7 @@ METHOD(mutex_t, unlock_r, void,
{ {
if (--this->times == 0) if (--this->times == 0)
{ {
memset(&this->thread, 0, sizeof(this->thread)); cas_ptr(&this->thread, thread_current(), NULL);
unlock(&this->generic); unlock(&this->generic);
} }
} }
@ -220,14 +221,15 @@ METHOD(condvar_t, wait_, void,
if (mutex->recursive) if (mutex->recursive)
{ {
private_r_mutex_t* recursive = (private_r_mutex_t*)mutex; private_r_mutex_t* recursive = (private_r_mutex_t*)mutex;
thread_t *self = thread_current();
u_int times; u_int times;
/* keep track of the number of times this thread locked the mutex */ /* keep track of the number of times this thread locked the mutex */
times = recursive->times; times = recursive->times;
/* mutex owner gets cleared during condvar wait */ /* mutex owner gets cleared during condvar wait */
memset(&recursive->thread, 0, sizeof(recursive->thread)); cas_ptr(&recursive->thread, self, NULL);
pthread_cond_wait(&this->condvar, &mutex->mutex); pthread_cond_wait(&this->condvar, &mutex->mutex);
recursive->thread = pthread_self(); cas_ptr(&recursive->thread, NULL, self);
recursive->times = times; recursive->times = times;
} }
else else
@ -253,13 +255,14 @@ METHOD(condvar_t, timed_wait_abs, bool,
if (mutex->recursive) if (mutex->recursive)
{ {
private_r_mutex_t* recursive = (private_r_mutex_t*)mutex; private_r_mutex_t* recursive = (private_r_mutex_t*)mutex;
thread_t *self = thread_current();
u_int times; u_int times;
times = recursive->times; times = recursive->times;
memset(&recursive->thread, 0, sizeof(recursive->thread)); cas_ptr(&recursive->thread, self, NULL);
timed_out = pthread_cond_timedwait(&this->condvar, &mutex->mutex, timed_out = pthread_cond_timedwait(&this->condvar, &mutex->mutex,
&ts) == ETIMEDOUT; &ts) == ETIMEDOUT;
recursive->thread = pthread_self(); cas_ptr(&recursive->thread, NULL, self);
recursive->times = times; recursive->times = times;
} }
else else