* _NewReadLockInfo() can no longer crash in case the allocation failed.
* _ReadLock() will now fail with B_NO_MEMORY in case the ReadLockInfo couldn't be created. * Note, due to a design bug, we cannot guarantee that a previous read lock can be reestablished after releasing a write lock in case of low memory. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17332 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
854026c907
commit
dde52de872
@ -15,30 +15,26 @@ struct RWLocker::ReadLockInfo {
|
|||||||
|
|
||||||
// constructor
|
// constructor
|
||||||
RWLocker::RWLocker()
|
RWLocker::RWLocker()
|
||||||
: fLock(),
|
:
|
||||||
fMutex(),
|
fReaderCount(0),
|
||||||
fQueue(),
|
fWriterCount(0),
|
||||||
fReaderCount(0),
|
fReadLockInfos(8),
|
||||||
fWriterCount(0),
|
fWriter(B_ERROR),
|
||||||
fReadLockInfos(8),
|
fWriterWriterCount(0),
|
||||||
fWriter(B_ERROR),
|
fWriterReaderCount(0)
|
||||||
fWriterWriterCount(0),
|
|
||||||
fWriterReaderCount(0)
|
|
||||||
{
|
{
|
||||||
_Init(NULL);
|
_Init(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// constructor
|
// constructor
|
||||||
RWLocker::RWLocker(const char* name)
|
RWLocker::RWLocker(const char* name)
|
||||||
: fLock(),
|
:
|
||||||
fMutex(),
|
fReaderCount(0),
|
||||||
fQueue(),
|
fWriterCount(0),
|
||||||
fReaderCount(0),
|
fReadLockInfos(8),
|
||||||
fWriterCount(0),
|
fWriter(B_ERROR),
|
||||||
fReadLockInfos(8),
|
fWriterWriterCount(0),
|
||||||
fWriter(B_ERROR),
|
fWriterReaderCount(0)
|
||||||
fWriterWriterCount(0),
|
|
||||||
fWriterReaderCount(0)
|
|
||||||
{
|
{
|
||||||
_Init(name);
|
_Init(name);
|
||||||
}
|
}
|
||||||
@ -49,8 +45,10 @@ RWLocker::~RWLocker()
|
|||||||
_AcquireBenaphore(fLock);
|
_AcquireBenaphore(fLock);
|
||||||
delete_sem(fMutex.semaphore);
|
delete_sem(fMutex.semaphore);
|
||||||
delete_sem(fQueue.semaphore);
|
delete_sem(fQueue.semaphore);
|
||||||
for (int32 i = 0; ReadLockInfo* info = _ReadLockInfoAt(i); i++)
|
for (int32 i = 0; ReadLockInfo* info = _ReadLockInfoAt(i); i++) {
|
||||||
delete info;
|
delete info;
|
||||||
|
}
|
||||||
|
|
||||||
delete_sem(fLock.semaphore);
|
delete_sem(fLock.semaphore);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,6 +62,7 @@ RWLocker::InitCheck() const
|
|||||||
return fMutex.semaphore;
|
return fMutex.semaphore;
|
||||||
if (fQueue.semaphore < 0)
|
if (fQueue.semaphore < 0)
|
||||||
return fQueue.semaphore;
|
return fQueue.semaphore;
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,10 +115,11 @@ RWLocker::ReadUnlock()
|
|||||||
} // else: we are probably going to be destroyed
|
} // else: we are probably going to be destroyed
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsReadLocked
|
|
||||||
//
|
/** Returns whether or not the calling thread owns a read lock or, if
|
||||||
// Returns whether or not the calling thread owns a read lock or, if
|
* orWriteLock is true, at least a write lock.
|
||||||
// orWriteLock is true, at least a write lock.
|
*/
|
||||||
|
|
||||||
bool
|
bool
|
||||||
RWLocker::IsReadLocked(bool orWriteLock) const
|
RWLocker::IsReadLocked(bool orWriteLock) const
|
||||||
{
|
{
|
||||||
@ -166,10 +166,13 @@ RWLocker::WriteUnlock()
|
|||||||
if (fWriterReaderCount > 0) {
|
if (fWriterReaderCount > 0) {
|
||||||
// We still own read locks.
|
// We still own read locks.
|
||||||
_NewReadLockInfo(thread, fWriterReaderCount);
|
_NewReadLockInfo(thread, fWriterReaderCount);
|
||||||
|
// TODO: if the creation fails, there is nothing we can do about it!
|
||||||
|
|
||||||
// A reader that expects to be the first reader may wait
|
// A reader that expects to be the first reader may wait
|
||||||
// at the mutex semaphore. We need to wake it up.
|
// at the mutex semaphore. We need to wake it up.
|
||||||
if (fReaderCount > 0)
|
if (fReaderCount > 0)
|
||||||
_ReleaseBenaphore(fMutex);
|
_ReleaseBenaphore(fMutex);
|
||||||
|
|
||||||
fReaderCount += fWriterReaderCount;
|
fReaderCount += fWriterReaderCount;
|
||||||
fWriterReaderCount = 0;
|
fWriterReaderCount = 0;
|
||||||
} else {
|
} else {
|
||||||
@ -183,9 +186,9 @@ RWLocker::WriteUnlock()
|
|||||||
} // else: We're probably going to die.
|
} // else: We're probably going to die.
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsWriteLocked
|
|
||||||
//
|
/** Returns whether or not the calling thread owns a write lock. */
|
||||||
// Returns whether or not the calling thread owns a write lock.
|
|
||||||
bool
|
bool
|
||||||
RWLocker::IsWriteLocked() const
|
RWLocker::IsWriteLocked() const
|
||||||
{
|
{
|
||||||
@ -193,8 +196,7 @@ RWLocker::IsWriteLocked() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
// make_sem_name
|
// make_sem_name
|
||||||
static
|
static void
|
||||||
void
|
|
||||||
make_sem_name(char *buffer, const char *name, const char *suffix)
|
make_sem_name(char *buffer, const char *name, const char *suffix)
|
||||||
{
|
{
|
||||||
if (!name)
|
if (!name)
|
||||||
@ -252,8 +254,11 @@ RWLocker::_ReadLock(bigtime_t timeout)
|
|||||||
locked = true;
|
locked = true;
|
||||||
}
|
}
|
||||||
_ReleaseBenaphore(fLock);
|
_ReleaseBenaphore(fLock);
|
||||||
} else // failed to lock the data
|
} else {
|
||||||
|
// failed to lock the data
|
||||||
error = B_ERROR;
|
error = B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
// Usual locking, i.e. we do not already own a read or write lock.
|
// Usual locking, i.e. we do not already own a read or write lock.
|
||||||
if (error == B_OK && !locked) {
|
if (error == B_OK && !locked) {
|
||||||
error = _AcquireBenaphore(fQueue, timeout);
|
error = _AcquireBenaphore(fQueue, timeout);
|
||||||
@ -262,11 +267,18 @@ RWLocker::_ReadLock(bigtime_t timeout)
|
|||||||
bool firstReader = false;
|
bool firstReader = false;
|
||||||
if (++fReaderCount == 1) {
|
if (++fReaderCount == 1) {
|
||||||
// We are the first reader.
|
// We are the first reader.
|
||||||
_NewReadLockInfo(thread);
|
|
||||||
firstReader = true;
|
firstReader = true;
|
||||||
} else
|
}
|
||||||
_NewReadLockInfo(thread);
|
|
||||||
|
int32 index = _NewReadLockInfo(thread);
|
||||||
_ReleaseBenaphore(fLock);
|
_ReleaseBenaphore(fLock);
|
||||||
|
|
||||||
|
if (index < 0) {
|
||||||
|
// creating a ReadLockInfo object failed
|
||||||
|
_ReleaseBenaphore(fQueue);
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
// The first reader needs to lock the mutex.
|
// The first reader needs to lock the mutex.
|
||||||
if (firstReader) {
|
if (firstReader) {
|
||||||
error = _AcquireBenaphore(fMutex, timeout);
|
error = _AcquireBenaphore(fMutex, timeout);
|
||||||
@ -399,6 +411,7 @@ RWLocker::_WriteLock(bigtime_t timeout)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Second step: acquire the mutex benaphore.
|
// Second step: acquire the mutex benaphore.
|
||||||
if (!locked && error == B_OK) {
|
if (!locked && error == B_OK) {
|
||||||
error = _AcquireBenaphore(fMutex, timeout);
|
error = _AcquireBenaphore(fMutex, timeout);
|
||||||
@ -440,14 +453,19 @@ RWLocker::_AddReadLockInfo(ReadLockInfo* info)
|
|||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
// _NewReadLockInfo
|
|
||||||
//
|
/** Create a new read lock info for the supplied thread and add it to
|
||||||
// Create a new read lock info for the supplied thread and add it to the
|
* the list. Returns the index of the info, or -1 to indicate an out
|
||||||
// list. Returns the index of the info.
|
* of memory situation.
|
||||||
|
*/
|
||||||
|
|
||||||
int32
|
int32
|
||||||
RWLocker::_NewReadLockInfo(thread_id thread, int32 count)
|
RWLocker::_NewReadLockInfo(thread_id thread, int32 count)
|
||||||
{
|
{
|
||||||
ReadLockInfo* info = new(nothrow) ReadLockInfo;
|
ReadLockInfo* info = new(nothrow) ReadLockInfo;
|
||||||
|
if (info == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
info->reader = thread;
|
info->reader = thread;
|
||||||
info->count = count;
|
info->count = count;
|
||||||
return _AddReadLockInfo(info);
|
return _AddReadLockInfo(info);
|
||||||
|
Loading…
Reference in New Issue
Block a user