RWLocker: Move to kits/shared.
As requested by looncraz. A lot of stuff in IOM/MediaPlayer's 'support' directories probably should be moved to 'shared' anyway.
This commit is contained in:
@@ -199,7 +199,6 @@ Application Icon-O-Matic :
|
|||||||
Selection.cpp
|
Selection.cpp
|
||||||
|
|
||||||
# generic/support
|
# generic/support
|
||||||
RWLocker.cpp
|
|
||||||
support.cpp
|
support.cpp
|
||||||
support_ui.cpp
|
support_ui.cpp
|
||||||
support_settings.cpp
|
support_settings.cpp
|
||||||
@@ -309,9 +308,9 @@ Application Icon-O-Matic :
|
|||||||
Includes [ FGristFiles SVGParser.cpp ]
|
Includes [ FGristFiles SVGParser.cpp ]
|
||||||
: [ BuildFeatureAttribute expat : headers ] ;
|
: [ BuildFeatureAttribute expat : headers ] ;
|
||||||
|
|
||||||
DoCatalogs Icon-O-Matic :
|
DoCatalogs Icon-O-Matic :
|
||||||
x-vnd.haiku-icon_o_matic
|
x-vnd.haiku-icon_o_matic
|
||||||
:
|
:
|
||||||
MainWindow.cpp
|
MainWindow.cpp
|
||||||
IconEditorApp.cpp
|
IconEditorApp.cpp
|
||||||
SetPropertiesCommand.cpp
|
SetPropertiesCommand.cpp
|
||||||
|
|||||||
@@ -101,7 +101,6 @@ Application MediaPlayer :
|
|||||||
ListenerAdapter.cpp
|
ListenerAdapter.cpp
|
||||||
MessageEvent.cpp
|
MessageEvent.cpp
|
||||||
Notifier.cpp
|
Notifier.cpp
|
||||||
RWLocker.cpp
|
|
||||||
SettingsMessage.cpp
|
SettingsMessage.cpp
|
||||||
StackBlurFilter.cpp
|
StackBlurFilter.cpp
|
||||||
|
|
||||||
@@ -114,14 +113,14 @@ Application MediaPlayer :
|
|||||||
MainWin.cpp
|
MainWin.cpp
|
||||||
VideoView.cpp
|
VideoView.cpp
|
||||||
|
|
||||||
: be game media tracker translation textencoding [ TargetLibstdc++ ]
|
: be game media tracker translation textencoding [ TargetLibstdc++ ]
|
||||||
localestub libshared.a
|
localestub libshared.a
|
||||||
: MediaPlayer.rdef
|
: MediaPlayer.rdef
|
||||||
;
|
;
|
||||||
|
|
||||||
DoCatalogs MediaPlayer :
|
DoCatalogs MediaPlayer :
|
||||||
x-vnd.Haiku-MediaPlayer
|
x-vnd.Haiku-MediaPlayer
|
||||||
:
|
:
|
||||||
CopyPLItemsCommand.cpp
|
CopyPLItemsCommand.cpp
|
||||||
ImportPLItemsCommand.cpp
|
ImportPLItemsCommand.cpp
|
||||||
InfoWin.cpp
|
InfoWin.cpp
|
||||||
|
|||||||
@@ -1,471 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2006, Haiku.
|
|
||||||
* Distributed under the terms of the MIT License.
|
|
||||||
*
|
|
||||||
* Authors:
|
|
||||||
* IngoWeinhold <[email protected]>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "RWLocker.h"
|
|
||||||
|
|
||||||
#include <String.h>
|
|
||||||
|
|
||||||
// info about a read lock owner
|
|
||||||
struct RWLocker::ReadLockInfo {
|
|
||||||
thread_id reader;
|
|
||||||
int32 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// constructor
|
|
||||||
RWLocker::RWLocker()
|
|
||||||
: fLock(),
|
|
||||||
fMutex(),
|
|
||||||
fQueue(),
|
|
||||||
fReaderCount(0),
|
|
||||||
fWriterCount(0),
|
|
||||||
fReadLockInfos(8),
|
|
||||||
fWriter(B_ERROR),
|
|
||||||
fWriterWriterCount(0),
|
|
||||||
fWriterReaderCount(0)
|
|
||||||
{
|
|
||||||
_Init(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// constructor
|
|
||||||
RWLocker::RWLocker(const char* name)
|
|
||||||
: fLock(name),
|
|
||||||
fMutex(),
|
|
||||||
fQueue(),
|
|
||||||
fReaderCount(0),
|
|
||||||
fWriterCount(0),
|
|
||||||
fReadLockInfos(8),
|
|
||||||
fWriter(B_ERROR),
|
|
||||||
fWriterWriterCount(0),
|
|
||||||
fWriterReaderCount(0)
|
|
||||||
{
|
|
||||||
_Init(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
// destructor
|
|
||||||
RWLocker::~RWLocker()
|
|
||||||
{
|
|
||||||
fLock.Lock();
|
|
||||||
delete_sem(fMutex.semaphore);
|
|
||||||
delete_sem(fQueue.semaphore);
|
|
||||||
for (int32 i = 0; ReadLockInfo* info = _ReadLockInfoAt(i); i++)
|
|
||||||
delete info;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadLock
|
|
||||||
bool
|
|
||||||
RWLocker::ReadLock()
|
|
||||||
{
|
|
||||||
status_t error = _ReadLock(B_INFINITE_TIMEOUT);
|
|
||||||
return (error == B_OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadLockWithTimeout
|
|
||||||
status_t
|
|
||||||
RWLocker::ReadLockWithTimeout(bigtime_t timeout)
|
|
||||||
{
|
|
||||||
bigtime_t absoluteTimeout = system_time() + timeout;
|
|
||||||
// take care of overflow
|
|
||||||
if (timeout > 0 && absoluteTimeout < 0)
|
|
||||||
absoluteTimeout = B_INFINITE_TIMEOUT;
|
|
||||||
return _ReadLock(absoluteTimeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadUnlock
|
|
||||||
void
|
|
||||||
RWLocker::ReadUnlock()
|
|
||||||
{
|
|
||||||
if (fLock.Lock()) {
|
|
||||||
thread_id thread = find_thread(NULL);
|
|
||||||
if (thread == fWriter) {
|
|
||||||
// We (also) have a write lock.
|
|
||||||
if (fWriterReaderCount > 0)
|
|
||||||
fWriterReaderCount--;
|
|
||||||
// else: error: unmatched ReadUnlock()
|
|
||||||
} else {
|
|
||||||
int32 index = _IndexOf(thread);
|
|
||||||
if (ReadLockInfo* info = _ReadLockInfoAt(index)) {
|
|
||||||
fReaderCount--;
|
|
||||||
if (--info->count == 0) {
|
|
||||||
// The outer read lock bracket for the thread has been
|
|
||||||
// reached. Dispose the info.
|
|
||||||
_DeleteReadLockInfo(index);
|
|
||||||
}
|
|
||||||
if (fReaderCount == 0) {
|
|
||||||
// The last reader needs to unlock the mutex.
|
|
||||||
_ReleaseBenaphore(fMutex);
|
|
||||||
}
|
|
||||||
} // else: error: caller has no read lock
|
|
||||||
}
|
|
||||||
fLock.Unlock();
|
|
||||||
} // else: we are probably going to be destroyed
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsReadLocked
|
|
||||||
//
|
|
||||||
// Returns whether or not the calling thread owns a read lock or even a
|
|
||||||
// write lock.
|
|
||||||
bool
|
|
||||||
RWLocker::IsReadLocked() const
|
|
||||||
{
|
|
||||||
bool result = false;
|
|
||||||
if (fLock.Lock()) {
|
|
||||||
thread_id thread = find_thread(NULL);
|
|
||||||
result = (thread == fWriter || _IndexOf(thread) >= 0);
|
|
||||||
fLock.Unlock();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteLock
|
|
||||||
bool
|
|
||||||
RWLocker::WriteLock()
|
|
||||||
{
|
|
||||||
status_t error = _WriteLock(B_INFINITE_TIMEOUT);
|
|
||||||
return (error == B_OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteLockWithTimeout
|
|
||||||
status_t
|
|
||||||
RWLocker::WriteLockWithTimeout(bigtime_t timeout)
|
|
||||||
{
|
|
||||||
bigtime_t absoluteTimeout = system_time() + timeout;
|
|
||||||
// take care of overflow
|
|
||||||
if (timeout > 0 && absoluteTimeout < 0)
|
|
||||||
absoluteTimeout = B_INFINITE_TIMEOUT;
|
|
||||||
return _WriteLock(absoluteTimeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteUnlock
|
|
||||||
void
|
|
||||||
RWLocker::WriteUnlock()
|
|
||||||
{
|
|
||||||
if (fLock.Lock()) {
|
|
||||||
thread_id thread = find_thread(NULL);
|
|
||||||
if (thread == fWriter) {
|
|
||||||
fWriterCount--;
|
|
||||||
if (--fWriterWriterCount == 0) {
|
|
||||||
// The outer write lock bracket for the thread has been
|
|
||||||
// reached.
|
|
||||||
fWriter = B_ERROR;
|
|
||||||
if (fWriterReaderCount > 0) {
|
|
||||||
// We still own read locks.
|
|
||||||
_NewReadLockInfo(thread, fWriterReaderCount);
|
|
||||||
// A reader that expects to be the first reader may wait
|
|
||||||
// at the mutex semaphore. We need to wake it up.
|
|
||||||
if (fReaderCount > 0)
|
|
||||||
_ReleaseBenaphore(fMutex);
|
|
||||||
fReaderCount += fWriterReaderCount;
|
|
||||||
fWriterReaderCount = 0;
|
|
||||||
} else {
|
|
||||||
// We don't own any read locks. So we have to release the
|
|
||||||
// mutex benaphore.
|
|
||||||
_ReleaseBenaphore(fMutex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // else: error: unmatched WriteUnlock()
|
|
||||||
fLock.Unlock();
|
|
||||||
} // else: We're probably going to die.
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsWriteLocked
|
|
||||||
//
|
|
||||||
// Returns whether or not the calling thread owns a write lock.
|
|
||||||
bool
|
|
||||||
RWLocker::IsWriteLocked() const
|
|
||||||
{
|
|
||||||
return (fWriter == find_thread(NULL));
|
|
||||||
}
|
|
||||||
|
|
||||||
// _Init
|
|
||||||
void
|
|
||||||
RWLocker::_Init(const char* name)
|
|
||||||
{
|
|
||||||
// init the mutex benaphore
|
|
||||||
BString mutexName(name);
|
|
||||||
mutexName += "_RWLocker_mutex";
|
|
||||||
fMutex.semaphore = create_sem(0, mutexName.String());
|
|
||||||
fMutex.counter = 0;
|
|
||||||
// init the queueing benaphore
|
|
||||||
BString queueName(name);
|
|
||||||
queueName += "_RWLocker_queue";
|
|
||||||
fQueue.semaphore = create_sem(0, queueName.String());
|
|
||||||
fQueue.counter = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// _ReadLock
|
|
||||||
//
|
|
||||||
// /timeout/ -- absolute timeout
|
|
||||||
status_t
|
|
||||||
RWLocker::_ReadLock(bigtime_t timeout)
|
|
||||||
{
|
|
||||||
status_t error = B_OK;
|
|
||||||
thread_id thread = find_thread(NULL);
|
|
||||||
bool locked = false;
|
|
||||||
if (fLock.Lock()) {
|
|
||||||
// Check, if we already own a read (or write) lock. In this case we
|
|
||||||
// can skip the usual locking procedure.
|
|
||||||
if (thread == fWriter) {
|
|
||||||
// We already own a write lock.
|
|
||||||
fWriterReaderCount++;
|
|
||||||
locked = true;
|
|
||||||
} else if (ReadLockInfo* info = _ReadLockInfoAt(_IndexOf(thread))) {
|
|
||||||
// We already own a read lock.
|
|
||||||
info->count++;
|
|
||||||
fReaderCount++;
|
|
||||||
locked = true;
|
|
||||||
}
|
|
||||||
fLock.Unlock();
|
|
||||||
} else // failed to lock the data
|
|
||||||
error = B_ERROR;
|
|
||||||
// Usual locking, i.e. we do not already own a read or write lock.
|
|
||||||
if (error == B_OK && !locked) {
|
|
||||||
error = _AcquireBenaphore(fQueue, timeout);
|
|
||||||
if (error == B_OK) {
|
|
||||||
if (fLock.Lock()) {
|
|
||||||
bool firstReader = false;
|
|
||||||
if (++fReaderCount == 1) {
|
|
||||||
// We are the first reader.
|
|
||||||
_NewReadLockInfo(thread);
|
|
||||||
firstReader = true;
|
|
||||||
} else
|
|
||||||
_NewReadLockInfo(thread);
|
|
||||||
fLock.Unlock();
|
|
||||||
// The first reader needs to lock the mutex.
|
|
||||||
if (firstReader) {
|
|
||||||
error = _AcquireBenaphore(fMutex, timeout);
|
|
||||||
switch (error) {
|
|
||||||
case B_OK:
|
|
||||||
// fine
|
|
||||||
break;
|
|
||||||
case B_TIMED_OUT: {
|
|
||||||
// clean up
|
|
||||||
if (fLock.Lock()) {
|
|
||||||
_DeleteReadLockInfo(_IndexOf(thread));
|
|
||||||
fReaderCount--;
|
|
||||||
fLock.Unlock();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
// Probably we are going to be destroyed.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Let the next candidate enter the game.
|
|
||||||
_ReleaseBenaphore(fQueue);
|
|
||||||
} else {
|
|
||||||
// We couldn't lock the data, which can only happen, if
|
|
||||||
// we're going to be destroyed.
|
|
||||||
error = B_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
// _WriteLock
|
|
||||||
//
|
|
||||||
// /timeout/ -- absolute timeout
|
|
||||||
status_t
|
|
||||||
RWLocker::_WriteLock(bigtime_t timeout)
|
|
||||||
{
|
|
||||||
status_t error = B_ERROR;
|
|
||||||
if (fLock.Lock()) {
|
|
||||||
bool infiniteTimeout = (timeout == B_INFINITE_TIMEOUT);
|
|
||||||
bool locked = false;
|
|
||||||
int32 readerCount = 0;
|
|
||||||
thread_id thread = find_thread(NULL);
|
|
||||||
int32 index = _IndexOf(thread);
|
|
||||||
if (ReadLockInfo* info = _ReadLockInfoAt(index)) {
|
|
||||||
// We already own a read lock.
|
|
||||||
if (fWriterCount > 0) {
|
|
||||||
// There are writers before us.
|
|
||||||
if (infiniteTimeout) {
|
|
||||||
// Timeout is infinite and there are writers before us.
|
|
||||||
// Unregister the read locks and lock as usual.
|
|
||||||
readerCount = info->count;
|
|
||||||
fWriterCount++;
|
|
||||||
fReaderCount -= readerCount;
|
|
||||||
_DeleteReadLockInfo(index);
|
|
||||||
error = B_OK;
|
|
||||||
} else {
|
|
||||||
// The timeout is finite and there are readers before us:
|
|
||||||
// let the write lock request fail.
|
|
||||||
error = B_WOULD_BLOCK;
|
|
||||||
}
|
|
||||||
} else if (info->count == fReaderCount) {
|
|
||||||
// No writers before us.
|
|
||||||
// We are the only read lock owners. Just move the read lock
|
|
||||||
// info data to the special writer fields and then we are done.
|
|
||||||
// Note: At this point we may overtake readers that already
|
|
||||||
// have acquired the queueing benaphore, but have not yet
|
|
||||||
// locked the data. But that doesn't harm.
|
|
||||||
fWriter = thread;
|
|
||||||
fWriterCount++;
|
|
||||||
fWriterWriterCount = 1;
|
|
||||||
fWriterReaderCount = info->count;
|
|
||||||
fReaderCount -= fWriterReaderCount;
|
|
||||||
_DeleteReadLockInfo(index);
|
|
||||||
locked = true;
|
|
||||||
error = B_OK;
|
|
||||||
} else {
|
|
||||||
// No writers before us, but other readers.
|
|
||||||
// Note, we're quite restrictive here. If there are only
|
|
||||||
// readers before us, we could reinstall our readers, if
|
|
||||||
// our request times out. Unfortunately it is not easy
|
|
||||||
// to ensure, that no writer overtakes us between unlocking
|
|
||||||
// the data and acquiring the queuing benaphore.
|
|
||||||
if (infiniteTimeout) {
|
|
||||||
// Unregister the readers and lock as usual.
|
|
||||||
readerCount = info->count;
|
|
||||||
fWriterCount++;
|
|
||||||
fReaderCount -= readerCount;
|
|
||||||
_DeleteReadLockInfo(index);
|
|
||||||
error = B_OK;
|
|
||||||
} else
|
|
||||||
error = B_WOULD_BLOCK;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// We don't own a read lock.
|
|
||||||
if (fWriter == thread) {
|
|
||||||
// ... but a write lock.
|
|
||||||
fWriterCount++;
|
|
||||||
fWriterWriterCount++;
|
|
||||||
locked = true;
|
|
||||||
error = B_OK;
|
|
||||||
} else {
|
|
||||||
// We own neither read nor write locks.
|
|
||||||
// Lock as usual.
|
|
||||||
fWriterCount++;
|
|
||||||
error = B_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fLock.Unlock();
|
|
||||||
// Usual locking...
|
|
||||||
// First step: acquire the queueing benaphore.
|
|
||||||
if (!locked && error == B_OK) {
|
|
||||||
error = _AcquireBenaphore(fQueue, timeout);
|
|
||||||
switch (error) {
|
|
||||||
case B_OK:
|
|
||||||
break;
|
|
||||||
case B_TIMED_OUT: {
|
|
||||||
// clean up
|
|
||||||
if (fLock.Lock()) {
|
|
||||||
fWriterCount--;
|
|
||||||
fLock.Unlock();
|
|
||||||
} // else: failed to lock the data: we're probably going
|
|
||||||
// to die.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
// Probably we're going to die.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Second step: acquire the mutex benaphore.
|
|
||||||
if (!locked && error == B_OK) {
|
|
||||||
error = _AcquireBenaphore(fMutex, timeout);
|
|
||||||
switch (error) {
|
|
||||||
case B_OK: {
|
|
||||||
// Yeah, we made it. Set the special writer fields.
|
|
||||||
fWriter = thread;
|
|
||||||
fWriterWriterCount = 1;
|
|
||||||
fWriterReaderCount = readerCount;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case B_TIMED_OUT: {
|
|
||||||
// clean up
|
|
||||||
if (fLock.Lock()) {
|
|
||||||
fWriterCount--;
|
|
||||||
fLock.Unlock();
|
|
||||||
} // else: failed to lock the data: we're probably going
|
|
||||||
// to die.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
// Probably we're going to die.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Whatever happened, we have to release the queueing benaphore.
|
|
||||||
_ReleaseBenaphore(fQueue);
|
|
||||||
}
|
|
||||||
} else // failed to lock the data
|
|
||||||
error = B_ERROR;
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
// _AddReadLockInfo
|
|
||||||
int32
|
|
||||||
RWLocker::_AddReadLockInfo(ReadLockInfo* info)
|
|
||||||
{
|
|
||||||
int32 index = fReadLockInfos.CountItems();
|
|
||||||
fReadLockInfos.AddItem(info, index);
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
// _NewReadLockInfo
|
|
||||||
//
|
|
||||||
// Create a new read lock info for the supplied thread and add it to the
|
|
||||||
// list. Returns the index of the info.
|
|
||||||
int32
|
|
||||||
RWLocker::_NewReadLockInfo(thread_id thread, int32 count)
|
|
||||||
{
|
|
||||||
ReadLockInfo* info = new ReadLockInfo;
|
|
||||||
info->reader = thread;
|
|
||||||
info->count = count;
|
|
||||||
return _AddReadLockInfo(info);
|
|
||||||
}
|
|
||||||
|
|
||||||
// _DeleteReadLockInfo
|
|
||||||
void
|
|
||||||
RWLocker::_DeleteReadLockInfo(int32 index)
|
|
||||||
{
|
|
||||||
if (ReadLockInfo* info = (ReadLockInfo*)fReadLockInfos.RemoveItem(index))
|
|
||||||
delete info;
|
|
||||||
}
|
|
||||||
|
|
||||||
// _ReadLockInfoAt
|
|
||||||
RWLocker::ReadLockInfo*
|
|
||||||
RWLocker::_ReadLockInfoAt(int32 index) const
|
|
||||||
{
|
|
||||||
return (ReadLockInfo*)fReadLockInfos.ItemAt(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
// _IndexOf
|
|
||||||
int32
|
|
||||||
RWLocker::_IndexOf(thread_id thread) const
|
|
||||||
{
|
|
||||||
int32 count = fReadLockInfos.CountItems();
|
|
||||||
for (int32 i = 0; i < count; i++) {
|
|
||||||
if (_ReadLockInfoAt(i)->reader == thread)
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// _AcquireBenaphore
|
|
||||||
status_t
|
|
||||||
RWLocker::_AcquireBenaphore(Benaphore& benaphore, bigtime_t timeout)
|
|
||||||
{
|
|
||||||
status_t error = B_OK;
|
|
||||||
if (atomic_add(&benaphore.counter, 1) > 0) {
|
|
||||||
error = acquire_sem_etc(benaphore.semaphore, 1, B_ABSOLUTE_TIMEOUT,
|
|
||||||
timeout);
|
|
||||||
}
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
// _ReleaseBenaphore
|
|
||||||
void
|
|
||||||
RWLocker::_ReleaseBenaphore(Benaphore& benaphore)
|
|
||||||
{
|
|
||||||
if (atomic_add(&benaphore.counter, -1) > 1)
|
|
||||||
release_sem(benaphore.semaphore);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,137 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2006, Haiku.
|
|
||||||
* Distributed under the terms of the MIT License.
|
|
||||||
*
|
|
||||||
* Authors:
|
|
||||||
* IngoWeinhold <[email protected]>
|
|
||||||
*/
|
|
||||||
|
|
||||||
// This class provides a reader/writer locking mechanism:
|
|
||||||
// * A writer needs an exclusive lock.
|
|
||||||
// * For a reader a non-exclusive lock to be shared with other readers is
|
|
||||||
// sufficient.
|
|
||||||
// * The ownership of a lock is bound to the thread that requested the lock;
|
|
||||||
// the same thread has to call Unlock() later.
|
|
||||||
// * Nested locking is supported: a number of XXXLock() calls needs to be
|
|
||||||
// bracketed by the same number of XXXUnlock() calls.
|
|
||||||
// * The lock acquiration strategy is fair: a lock applicant needs to wait
|
|
||||||
// only for those threads that already own a lock or requested one before
|
|
||||||
// the current thread. No one can overtake. E.g. if a thread owns a read
|
|
||||||
// lock, another one is waiting for a write lock, then a third one
|
|
||||||
// requesting a read lock has to wait until the write locker is done.
|
|
||||||
// This does not hold for threads that already own a lock (nested locking).
|
|
||||||
// A read lock owner is immediately granted another read lock and a write
|
|
||||||
// lock owner another write or a read lock.
|
|
||||||
// * A write lock owner is allowed to request a read lock and a read lock
|
|
||||||
// owner a write lock. While the first case is not problematic, the
|
|
||||||
// second one needs some further explanation: A read lock owner requesting
|
|
||||||
// a write lock temporarily looses its read lock(s) until the write lock
|
|
||||||
// is granted. Otherwise two read lock owning threads trying to get
|
|
||||||
// write locks at the same time would dead lock each other. The only
|
|
||||||
// problem with this solution is, that the write lock acquiration must
|
|
||||||
// not fail, because in that case the thread could not be given back
|
|
||||||
// its read lock(s), since another thread may have been given a write lock
|
|
||||||
// in the mean time. Fortunately locking can fail only either, if the
|
|
||||||
// locker has been deleted, or, if a timeout occured. Therefore
|
|
||||||
// WriteLockWithTimeout() immediatlely returns with a B_WOULD_BLOCK error
|
|
||||||
// code, if the caller already owns a read lock (but no write lock) and
|
|
||||||
// another thread already owns or has requested a read or write lock.
|
|
||||||
// * Calls to read and write locking methods may interleave arbitrarily,
|
|
||||||
// e.g.: ReadLock(); WriteLock(); ReadUnlock(); WriteUnlock();
|
|
||||||
//
|
|
||||||
// Important note: Read/WriteLock() can fail only, if the locker has been
|
|
||||||
// deleted. However, it is NOT save to invoke any method on a deleted
|
|
||||||
// locker object.
|
|
||||||
//
|
|
||||||
// Implementation details:
|
|
||||||
// A locker needs three semaphores (a BLocker and two semaphores): one
|
|
||||||
// to protect the lockers data, one as a reader/writer mutex (to be
|
|
||||||
// acquired by each writer and the first reader) and one for queueing
|
|
||||||
// waiting readers and writers. The simplified locking/unlocking
|
|
||||||
// algorithm is the following:
|
|
||||||
//
|
|
||||||
// writer reader
|
|
||||||
// queue.acquire() queue.acquire()
|
|
||||||
// mutex.acquire() if (first reader) mutex.acquire()
|
|
||||||
// queue.release() queue.release()
|
|
||||||
// ... ...
|
|
||||||
// mutex.release() if (last reader) mutex.release()
|
|
||||||
//
|
|
||||||
// One thread at maximum waits at the mutex, the others at the queueing
|
|
||||||
// semaphore. Unfortunately features as nested locking and timeouts make
|
|
||||||
// things more difficult. Therefore readers as well as writers need to check
|
|
||||||
// whether they already own a lock before acquiring the queueing semaphore.
|
|
||||||
// The data for the readers are stored in a list of ReadLockInfo structures;
|
|
||||||
// the writer data are stored in some special fields. /fReaderCount/ and
|
|
||||||
// /fWriterCount/ contain the total count of unbalanced Read/WriteLock()
|
|
||||||
// calls, /fWriterReaderCount/ and /fWriterWriterCount/ only from those of
|
|
||||||
// the current write lock owner (/fWriter/). To be a bit more precise:
|
|
||||||
// /fWriterReaderCount/ is not contained in /fReaderCount/, but
|
|
||||||
// /fWriterWriterCount/ is contained in /fWriterCount/. Therefore
|
|
||||||
// /fReaderCount/ can be considered to be the count of true reader's read
|
|
||||||
// locks.
|
|
||||||
|
|
||||||
#ifndef RW_LOCKER_H
|
|
||||||
#define RW_LOCKER_H
|
|
||||||
|
|
||||||
#include <List.h>
|
|
||||||
#include <Locker.h>
|
|
||||||
|
|
||||||
#include "AutoLocker.h"
|
|
||||||
|
|
||||||
class RWLocker {
|
|
||||||
public:
|
|
||||||
RWLocker();
|
|
||||||
RWLocker(const char* name);
|
|
||||||
virtual ~RWLocker();
|
|
||||||
|
|
||||||
bool ReadLock();
|
|
||||||
status_t ReadLockWithTimeout(bigtime_t timeout);
|
|
||||||
void ReadUnlock();
|
|
||||||
bool IsReadLocked() const;
|
|
||||||
|
|
||||||
bool WriteLock();
|
|
||||||
status_t WriteLockWithTimeout(bigtime_t timeout);
|
|
||||||
void WriteUnlock();
|
|
||||||
bool IsWriteLocked() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct ReadLockInfo;
|
|
||||||
struct Benaphore {
|
|
||||||
sem_id semaphore;
|
|
||||||
int32 counter;
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
void _Init(const char* name);
|
|
||||||
status_t _ReadLock(bigtime_t timeout);
|
|
||||||
status_t _WriteLock(bigtime_t timeout);
|
|
||||||
|
|
||||||
int32 _AddReadLockInfo(ReadLockInfo* info);
|
|
||||||
int32 _NewReadLockInfo(thread_id thread,
|
|
||||||
int32 count = 1);
|
|
||||||
void _DeleteReadLockInfo(int32 index);
|
|
||||||
ReadLockInfo* _ReadLockInfoAt(int32 index) const;
|
|
||||||
int32 _IndexOf(thread_id thread) const;
|
|
||||||
|
|
||||||
static status_t _AcquireBenaphore(Benaphore& benaphore,
|
|
||||||
bigtime_t timeout);
|
|
||||||
static void _ReleaseBenaphore(Benaphore& benaphore);
|
|
||||||
|
|
||||||
private:
|
|
||||||
mutable BLocker fLock; // data lock
|
|
||||||
Benaphore fMutex; // critical code mutex
|
|
||||||
Benaphore fQueue; // queueing semaphore
|
|
||||||
int32 fReaderCount; // total count...
|
|
||||||
int32 fWriterCount; // total count...
|
|
||||||
BList fReadLockInfos;
|
|
||||||
thread_id fWriter; // current write lock owner
|
|
||||||
int32 fWriterWriterCount; // write lock owner count
|
|
||||||
int32 fWriterReaderCount; // writer read lock owner
|
|
||||||
// count
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef AutoLocker<RWLocker, AutoLockerReadLocking<RWLocker> > AutoReadLocker;
|
|
||||||
typedef AutoLocker<RWLocker, AutoLockerWriteLocking<RWLocker> > AutoWriteLocker;
|
|
||||||
|
|
||||||
#endif // RW_LOCKER_H
|
|
||||||
@@ -46,6 +46,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
|
|||||||
PromptWindow.cpp
|
PromptWindow.cpp
|
||||||
QueryFile.cpp
|
QueryFile.cpp
|
||||||
RegExp.cpp
|
RegExp.cpp
|
||||||
|
RWLocker.cpp
|
||||||
RWLockManager.cpp
|
RWLockManager.cpp
|
||||||
SHA256.cpp
|
SHA256.cpp
|
||||||
ShakeTrackingFilter.cpp
|
ShakeTrackingFilter.cpp
|
||||||
|
|||||||
Reference in New Issue
Block a user