aboutsummaryrefslogtreecommitdiffstats
path: root/src/libstrongswan
diff options
context:
space:
mode:
authorTobias Brunner <tobias@strongswan.org>2012-01-21 16:11:28 +0100
committerTobias Brunner <tobias@strongswan.org>2012-05-02 14:45:38 +0200
commit4d21000cf71c9f89d81c1c54a0fc11be7a0c04b2 (patch)
tree8ba607cd86fcbd94b08ddf003e39c0e8c5367bb8 /src/libstrongswan
parent0e474f9148deebcd3a24205f0110c884c9b67f60 (diff)
downloadstrongswan-4d21000cf71c9f89d81c1c54a0fc11be7a0c04b2.tar.bz2
strongswan-4d21000cf71c9f89d81c1c54a0fc11be7a0c04b2.tar.xz
Added recursive read_lock support to our own implementation of rwlock_t.
Diffstat (limited to 'src/libstrongswan')
-rw-r--r--src/libstrongswan/threading/rwlock.c39
1 files changed, 35 insertions, 4 deletions
diff --git a/src/libstrongswan/threading/rwlock.c b/src/libstrongswan/threading/rwlock.c
index 15dc0b334..e0d727b65 100644
--- a/src/libstrongswan/threading/rwlock.c
+++ b/src/libstrongswan/threading/rwlock.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008-2009 Tobias Brunner
+ * Copyright (C) 2008-2012 Tobias Brunner
* Copyright (C) 2008 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -23,6 +23,7 @@
#include "rwlock.h"
#include "condvar.h"
#include "mutex.h"
+#include "thread_value.h"
#include "lock_profiler.h"
typedef struct private_rwlock_t private_rwlock_t;
@@ -62,6 +63,11 @@ struct private_rwlock_t {
condvar_t *readers;
/**
+ * thread local value to keep track whether the current thread is a reader
+ */
+ thread_value_t *is_reading;
+
+ /**
* number of waiting writers
*/
u_int waiting_writers;
@@ -189,14 +195,24 @@ rwlock_t *rwlock_create(rwlock_type_t type)
* 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).
+ * The implementation supports recursive locking of the read lock but not of
+ * the write lock. 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).
*/
METHOD(rwlock_t, read_lock, void,
private_rwlock_t *this)
{
+ uintptr_t reading;
+
+ reading = (uintptr_t)this->is_reading->get(this->is_reading);
+ if (reading > 0)
+ { /* we allow readers to acquire the lock recursively */
+ this->is_reading->set(this->is_reading, (void*)(reading + 1));
+ return;
+ }
+
profiler_start(&this->profile);
this->mutex->lock(this->mutex);
while (this->writer || this->waiting_writers)
@@ -206,6 +222,8 @@ METHOD(rwlock_t, read_lock, void,
this->reader_count++;
profiler_end(&this->profile);
this->mutex->unlock(this->mutex);
+
+ this->is_reading->set(this->is_reading, (void*)1);
}
METHOD(rwlock_t, write_lock, void,
@@ -241,6 +259,15 @@ METHOD(rwlock_t, try_write_lock, bool,
METHOD(rwlock_t, unlock, void,
private_rwlock_t *this)
{
+ uintptr_t reading;
+
+ reading = (uintptr_t)this->is_reading->get(this->is_reading);
+ if (reading > 1)
+ { /* readers have to unlock an equal number of times */
+ this->is_reading->set(this->is_reading, (void*)(reading - 1));
+ return;
+ }
+
this->mutex->lock(this->mutex);
if (this->writer == pthread_self())
{
@@ -263,6 +290,8 @@ METHOD(rwlock_t, unlock, void,
}
}
this->mutex->unlock(this->mutex);
+
+ this->is_reading->set(this->is_reading, NULL);
}
METHOD(rwlock_t, destroy, void,
@@ -271,6 +300,7 @@ METHOD(rwlock_t, destroy, void,
this->mutex->destroy(this->mutex);
this->writers->destroy(this->writers);
this->readers->destroy(this->readers);
+ this->is_reading->destroy(this->is_reading);
profiler_cleanup(&this->profile);
free(this);
}
@@ -298,6 +328,7 @@ rwlock_t *rwlock_create(rwlock_type_t type)
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
.writers = condvar_create(CONDVAR_TYPE_DEFAULT),
.readers = condvar_create(CONDVAR_TYPE_DEFAULT),
+ .is_reading = thread_value_create(NULL),
);
profiler_init(&this->profile);