mirror of
https://github.com/strongswan/strongswan.git
synced 2025-10-08 00:02:03 -04:00
Added recursive read_lock support to our own implementation of rwlock_t.
This commit is contained in:
parent
0e474f9148
commit
4d21000cf7
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2008-2009 Tobias Brunner
|
* Copyright (C) 2008-2012 Tobias Brunner
|
||||||
* Copyright (C) 2008 Martin Willi
|
* Copyright (C) 2008 Martin Willi
|
||||||
* Hochschule fuer Technik Rapperswil
|
* Hochschule fuer Technik Rapperswil
|
||||||
*
|
*
|
||||||
@ -23,6 +23,7 @@
|
|||||||
#include "rwlock.h"
|
#include "rwlock.h"
|
||||||
#include "condvar.h"
|
#include "condvar.h"
|
||||||
#include "mutex.h"
|
#include "mutex.h"
|
||||||
|
#include "thread_value.h"
|
||||||
#include "lock_profiler.h"
|
#include "lock_profiler.h"
|
||||||
|
|
||||||
typedef struct private_rwlock_t private_rwlock_t;
|
typedef struct private_rwlock_t private_rwlock_t;
|
||||||
@ -61,6 +62,11 @@ struct private_rwlock_t {
|
|||||||
*/
|
*/
|
||||||
condvar_t *readers;
|
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
|
* number of 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
|
* of incoming readers. Reader starvation is not prevented (this could happen
|
||||||
* if there are more writers than readers).
|
* if there are more writers than readers).
|
||||||
*
|
*
|
||||||
* The implementation does not support recursive locking and readers must not
|
* The implementation supports recursive locking of the read lock but not of
|
||||||
* acquire the lock exclusively at the same time and vice-versa (this is not
|
* the write lock. Readers must not acquire the lock exclusively at the same
|
||||||
* checked or enforced so behave yourself to prevent deadlocks).
|
* time and vice-versa (this is not checked or enforced so behave yourself to
|
||||||
|
* prevent deadlocks).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
METHOD(rwlock_t, read_lock, void,
|
METHOD(rwlock_t, read_lock, void,
|
||||||
private_rwlock_t *this)
|
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);
|
profiler_start(&this->profile);
|
||||||
this->mutex->lock(this->mutex);
|
this->mutex->lock(this->mutex);
|
||||||
while (this->writer || this->waiting_writers)
|
while (this->writer || this->waiting_writers)
|
||||||
@ -206,6 +222,8 @@ METHOD(rwlock_t, read_lock, void,
|
|||||||
this->reader_count++;
|
this->reader_count++;
|
||||||
profiler_end(&this->profile);
|
profiler_end(&this->profile);
|
||||||
this->mutex->unlock(this->mutex);
|
this->mutex->unlock(this->mutex);
|
||||||
|
|
||||||
|
this->is_reading->set(this->is_reading, (void*)1);
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(rwlock_t, write_lock, void,
|
METHOD(rwlock_t, write_lock, void,
|
||||||
@ -241,6 +259,15 @@ METHOD(rwlock_t, try_write_lock, bool,
|
|||||||
METHOD(rwlock_t, unlock, void,
|
METHOD(rwlock_t, unlock, void,
|
||||||
private_rwlock_t *this)
|
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);
|
this->mutex->lock(this->mutex);
|
||||||
if (this->writer == pthread_self())
|
if (this->writer == pthread_self())
|
||||||
{
|
{
|
||||||
@ -263,6 +290,8 @@ METHOD(rwlock_t, unlock, void,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this->mutex->unlock(this->mutex);
|
this->mutex->unlock(this->mutex);
|
||||||
|
|
||||||
|
this->is_reading->set(this->is_reading, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(rwlock_t, destroy, void,
|
METHOD(rwlock_t, destroy, void,
|
||||||
@ -271,6 +300,7 @@ METHOD(rwlock_t, destroy, void,
|
|||||||
this->mutex->destroy(this->mutex);
|
this->mutex->destroy(this->mutex);
|
||||||
this->writers->destroy(this->writers);
|
this->writers->destroy(this->writers);
|
||||||
this->readers->destroy(this->readers);
|
this->readers->destroy(this->readers);
|
||||||
|
this->is_reading->destroy(this->is_reading);
|
||||||
profiler_cleanup(&this->profile);
|
profiler_cleanup(&this->profile);
|
||||||
free(this);
|
free(this);
|
||||||
}
|
}
|
||||||
@ -298,6 +328,7 @@ rwlock_t *rwlock_create(rwlock_type_t type)
|
|||||||
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
|
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
|
||||||
.writers = condvar_create(CONDVAR_TYPE_DEFAULT),
|
.writers = condvar_create(CONDVAR_TYPE_DEFAULT),
|
||||||
.readers = condvar_create(CONDVAR_TYPE_DEFAULT),
|
.readers = condvar_create(CONDVAR_TYPE_DEFAULT),
|
||||||
|
.is_reading = thread_value_create(NULL),
|
||||||
);
|
);
|
||||||
|
|
||||||
profiler_init(&this->profile);
|
profiler_init(&this->profile);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user