ReadWriteLock

Implements a simple many readers and single writer lock for threads of a single process.

Summary
ReadWriteLockImplements a simple many readers and single writer lock for threads of a single process.
CopyrightThis program is free software.
Files
C-kern/api/platform/sync/rwlock.hHeader file ReadWriteLock.
C-kern/platform/Linux/sync/rwlock.cImplementation file ReadWriteLock Linuximpl.
Types
struct rwlock_tExport rwlock_t into global namespace.
Functions
test
unittest_platform_sync_rwlockTest rwlock_t functionality.
rwlock_tProtect a data structure from access of threads of a single process.
readersPoints to last entry in list of waiting readers.
writersPoints to last entry in list of waiting writers.
writerThe thread which holds <entrylock>.
nrofreaderThe number of readers currently reading the protected data structure.
lockflagLock flag used to protect access to data members.
lifetime
rwlock_FREEStatic initializer.
rwlock_INITStatic initializer.
init_rwlockInitializes data members.
free_rwlockFrees mutex.
query
nrofreader_rwlockReturns the number of readers holding the lock.
iswriter_rwlockReturns true if there is a single writer holding the lock.
synchronize
lockreader_rwlockAcquire <entrylock>, increment nrofreader and release <entrylock>.
lockwriter_rwlockAcquire <entrylock>, sets writer to seld and wait until nrofreader == 0.
unlockreader_rwlockAcquire <exitlock>, decrement nrofreader and return.
unlockwriter_rwlockSets writer to 0 and unlocks <entrylock>.
safe-synchronize
slockreader_rwlockAsserts that lockreader_rwlock has no error.
slockwriter_rwlockAsserts that lockwriter_rwlock has no error.
sunlockreader_rwlockAsserts that unlockreader_rwlock has no error.
sunlockwriter_rwlockAsserts that unlockwriter_rwlock has no error.
inline implementation
Macros
init_rwlockImplements rwlock_t.init_rwlock.
slockreader_rwlockImplements rwlock_t.slockreader_rwlock.
slockwriter_rwlockImplements rwlock_t.slockwriter_rwlock.
sunlockreader_rwlockImplements rwlock_t.sunlockreader_rwlock.
sunlockwriter_rwlockImplements rwlock_t.sunlockwriter_rwlock.

Copyright

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 Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.

Author

© 2013 Jörg Seebohn

Files

C-kern/api/platform/sync/rwlock.h

Header file ReadWriteLock.

C-kern/platform/Linux/sync/rwlock.c

Implementation file ReadWriteLock Linuximpl.

Types

struct rwlock_t

typedef struct rwlock_t rwlock_t

Export rwlock_t into global namespace.

Functions

test

unittest_platform_sync_rwlock

int unittest_platform_sync_rwlock(void)

Test rwlock_t functionality.

rwlock_t

struct rwlock_t

Protect a data structure from access of threads of a single process.  Either a single writer is allowed to enter the protected area or one or more readers are allowed to enter.  As long as no writer tries to acquire this lock no reader has to wait.  If a writer tries to acquire this type of lock it has to wait until all readers have released the lock.  A writer inserts itself in waiting list writers.  If at least a single writer waits all calls to lockreader_rwlock inserts the reader into the the readers waiting list.

The last reader which calls unlockreader_rwlock resumes a waiting writer.

During this time all other parties (reader or writer) have to wait until all readers and the single writer have released the lock.

A call unlockwriter_rwlock wakes up first any waiting reader.

So a writer releasing the lock wakes up all readers.  The last reader releasing the lock wakes up the first waiting writer.

Implementation Notes

The implementation an atomic lockflag.  Every call to lockreader_rwlock, lockwriter_rwlock, unlockreader_rwlock and unlockwriter_rwlock acquires this lock.  At the end they release the lock.

If during operation of unlockreader_rwlock or unlockwriter_rwlock a writer or reader is woken up the woken up thread acquires lockflag and releases it.  This ensures that any data written by the caller to unlockwriter_rwlock and any data written within the functions unlockreader_rwlock or unlockwriter_rwlock are known to the woken up thread.

Summary
readersPoints to last entry in list of waiting readers.
writersPoints to last entry in list of waiting writers.
writerThe thread which holds <entrylock>.
nrofreaderThe number of readers currently reading the protected data structure.
lockflagLock flag used to protect access to data members.
lifetime
rwlock_FREEStatic initializer.
rwlock_INITStatic initializer.
init_rwlockInitializes data members.
free_rwlockFrees mutex.
query
nrofreader_rwlockReturns the number of readers holding the lock.
iswriter_rwlockReturns true if there is a single writer holding the lock.
synchronize
lockreader_rwlockAcquire <entrylock>, increment nrofreader and release <entrylock>.
lockwriter_rwlockAcquire <entrylock>, sets writer to seld and wait until nrofreader == 0.
unlockreader_rwlockAcquire <exitlock>, decrement nrofreader and return.
unlockwriter_rwlockSets writer to 0 and unlocks <entrylock>.
safe-synchronize
slockreader_rwlockAsserts that lockreader_rwlock has no error.
slockwriter_rwlockAsserts that lockwriter_rwlock has no error.
sunlockreader_rwlockAsserts that unlockreader_rwlock has no error.
sunlockwriter_rwlockAsserts that unlockwriter_rwlock has no error.

readers

struct { struct slist_node_t * last ; } readers

Points to last entry in list of waiting readers.  Threads which can not lock rwlock for reading are appended to the end of the list.

writers

struct { struct slist_node_t * last ; } writers

Points to last entry in list of waiting writers.  Threads which can not lock rwlock for writing are appended to the end of the list.

writer

struct thread_t * writer

The thread which holds <entrylock>.  If nrofreader is greater 0 it is in suspended state.

nrofreader

uint32_t nrofreader

The number of readers currently reading the protected data structure.  If this value is no reader has acquired this lock.

lockflag

uint8_t lockflag

Lock flag used to protect access to data members.  Set and cleared with atomic operations.

lifetime

rwlock_FREE

#define rwlock_FREE { { 0 } , { 0 }, 0, 0, 0 }

Static initializer.

rwlock_INIT

#define rwlock_INIT { { 0 } , { 0 }, 0, 0, 0 }

Static initializer.

init_rwlock

void init_rwlock(/*out*/rwlock_t *rwlock)

Initializes data members.  The same as assigning rwlock_INIT.

free_rwlock

int free_rwlock(rwlock_t *rwlock)

Frees mutex.  Make sure that no readers nor writers are waiting for rwlock or holding rwlock.  The behaviour in such a case is undefined.  A mutex returns EBUSY and is not freed if someone holds it.

query

nrofreader_rwlock

uint32_t nrofreader_rwlock(rwlock_t *rwlock)

Returns the number of readers holding the lock.

iswriter_rwlock

bool iswriter_rwlock(rwlock_t *rwlock)

Returns true if there is a single writer holding the lock.

synchronize

lockreader_rwlock

int lockreader_rwlock(rwlock_t *rwlock)

Acquire <entrylock>, increment nrofreader and release <entrylock>.  After return nrofreader is > 0 and means a region is protected for reading.  A return value of EOVERFLOW indicates that nrofreader == UINT32_MAX and no more reader is allowed to enter.

lockwriter_rwlock

int lockwriter_rwlock(rwlock_t *rwlock)

Acquire <entrylock>, sets writer to seld and wait until nrofreader == 0.  If nrofreader > 0 the calling thread is suspended and the last reader leaving the protected region with unlockreader_rwlock resumes the waiting writer.

After the writer has been resumed it acquires <exitlock> to ensure that it read a current nrofreader and releases <exitlock>.  This also prevents a race condition if a spurious resume (suprious signal) wakes up the writer but the reader has not send the resume to the waiter.  If nrofreader equals 0 the call returns else the caller is suspend again.

unlockreader_rwlock

int unlockreader_rwlock(rwlock_t *rwlock)

Acquire <exitlock>, decrement nrofreader and return.  Call this function only after calling lockreader_rwlock.  If you forget one call nrofreader is wrong and no writer or other reader is allowed to enter.

unlockwriter_rwlock

int unlockwriter_rwlock(rwlock_t *rwlock)

Sets writer to 0 and unlocks <entrylock>.  Other writers or readers are allowed to enter (entrylock is unlocked).  Call this function only after calling lockwriter_rwlock else EPERM is returned and writer is not changed.

safe-synchronize

slockreader_rwlock

void slockreader_rwlock(rwlock_t *rwlock)

Asserts that lockreader_rwlock has no error.

slockwriter_rwlock

void slockwriter_rwlock(rwlock_t *rwlock)

Asserts that lockwriter_rwlock has no error.

sunlockreader_rwlock

void sunlockreader_rwlock(rwlock_t *rwlock)

Asserts that unlockreader_rwlock has no error.

sunlockwriter_rwlock

void sunlockwriter_rwlock(rwlock_t *rwlock)

Asserts that unlockwriter_rwlock has no error.

Macros

init_rwlock

#define init_rwlock(rwlock) ((void)(*(rwlock) = (rwlock_t) rwlock_INIT))

Implements rwlock_t.init_rwlock.

slockreader_rwlock

#define slockreader_rwlock(rwlock) (assert(!lockreader_rwlock(rwlock)))

Implements rwlock_t.slockreader_rwlock.

slockwriter_rwlock

#define slockwriter_rwlock(rwlock) (assert(!lockwriter_rwlock(rwlock)))

Implements rwlock_t.slockwriter_rwlock.

sunlockreader_rwlock

#define sunlockreader_rwlock(rwlock) (assert(!unlockreader_rwlock(rwlock)))

Implements rwlock_t.sunlockreader_rwlock.

sunlockwriter_rwlock

#define sunlockwriter_rwlock(rwlock) (assert(!unlockwriter_rwlock(rwlock)))

Implements rwlock_t.sunlockwriter_rwlock.

Implements a simple many readers and single writer lock for threads of a single process.
Implements ReadWriteLock.
typedef struct rwlock_t rwlock_t
Export rwlock_t into global namespace.
struct rwlock_t
Protect a data structure from access of threads of a single process.
int unittest_platform_sync_rwlock(void)
Test rwlock_t functionality.
struct { struct slist_node_t * last ; } readers
Points to last entry in list of waiting readers.
struct { struct slist_node_t * last ; } writers
Points to last entry in list of waiting writers.
struct thread_t * writer
The thread which holds entrylock.
uint32_t nrofreader
The number of readers currently reading the protected data structure.
uint8_t lockflag
Lock flag used to protect access to data members.
#define rwlock_FREE { { 0 } , { 0 }, 0, 0, 0 }
Static initializer.
#define rwlock_INIT { { 0 } , { 0 }, 0, 0, 0 }
Static initializer.
void init_rwlock(/*out*/rwlock_t *rwlock)
Initializes data members.
int free_rwlock(rwlock_t *rwlock)
Frees mutex.
uint32_t nrofreader_rwlock(rwlock_t *rwlock)
Returns the number of readers holding the lock.
bool iswriter_rwlock(rwlock_t *rwlock)
Returns true if there is a single writer holding the lock.
int lockreader_rwlock(rwlock_t *rwlock)
Acquire entrylock, increment nrofreader and release entrylock.
int lockwriter_rwlock(rwlock_t *rwlock)
Acquire entrylock, sets writer to seld and wait until nrofreader == 0.
int unlockreader_rwlock(rwlock_t *rwlock)
Acquire exitlock, decrement nrofreader and return.
int unlockwriter_rwlock(rwlock_t *rwlock)
Sets writer to 0 and unlocks entrylock.
void slockreader_rwlock(rwlock_t *rwlock)
Asserts that lockreader_rwlock has no error.
void slockwriter_rwlock(rwlock_t *rwlock)
Asserts that lockwriter_rwlock has no error.
void sunlockreader_rwlock(rwlock_t *rwlock)
Asserts that unlockreader_rwlock has no error.
void sunlockwriter_rwlock(rwlock_t *rwlock)
Asserts that unlockwriter_rwlock has no error.
#define init_rwlock(rwlock) ((void)(*(rwlock) = (rwlock_t) rwlock_INIT))
Implements rwlock_t.init_rwlock.
#define slockreader_rwlock(rwlock) (assert(!lockreader_rwlock(rwlock)))
Implements rwlock_t.slockreader_rwlock.
#define slockwriter_rwlock(rwlock) (assert(!lockwriter_rwlock(rwlock)))
Implements rwlock_t.slockwriter_rwlock.
#define sunlockreader_rwlock(rwlock) (assert(!unlockreader_rwlock(rwlock)))
Implements rwlock_t.sunlockreader_rwlock.
#define sunlockwriter_rwlock(rwlock) (assert(!unlockwriter_rwlock(rwlock)))
Implements rwlock_t.sunlockwriter_rwlock.
Close