From dde52de872dc09e584a2e2596c7518485597467d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Fri, 5 May 2006 10:10:05 +0000 Subject: [PATCH] * _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 --- .../kernel/disk_device_manager/RWLocker.cpp | 90 +++++++++++-------- 1 file changed, 54 insertions(+), 36 deletions(-) diff --git a/src/system/kernel/disk_device_manager/RWLocker.cpp b/src/system/kernel/disk_device_manager/RWLocker.cpp index e5a1108734..37cadaa55a 100644 --- a/src/system/kernel/disk_device_manager/RWLocker.cpp +++ b/src/system/kernel/disk_device_manager/RWLocker.cpp @@ -15,30 +15,26 @@ struct RWLocker::ReadLockInfo { // constructor RWLocker::RWLocker() - : fLock(), - fMutex(), - fQueue(), - fReaderCount(0), - fWriterCount(0), - fReadLockInfos(8), - fWriter(B_ERROR), - fWriterWriterCount(0), - fWriterReaderCount(0) + : + fReaderCount(0), + fWriterCount(0), + fReadLockInfos(8), + fWriter(B_ERROR), + fWriterWriterCount(0), + fWriterReaderCount(0) { _Init(NULL); } // constructor RWLocker::RWLocker(const char* name) - : fLock(), - fMutex(), - fQueue(), - fReaderCount(0), - fWriterCount(0), - fReadLockInfos(8), - fWriter(B_ERROR), - fWriterWriterCount(0), - fWriterReaderCount(0) + : + fReaderCount(0), + fWriterCount(0), + fReadLockInfos(8), + fWriter(B_ERROR), + fWriterWriterCount(0), + fWriterReaderCount(0) { _Init(name); } @@ -49,8 +45,10 @@ RWLocker::~RWLocker() _AcquireBenaphore(fLock); delete_sem(fMutex.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_sem(fLock.semaphore); } @@ -64,6 +62,7 @@ RWLocker::InitCheck() const return fMutex.semaphore; if (fQueue.semaphore < 0) return fQueue.semaphore; + return B_OK; } @@ -116,10 +115,11 @@ RWLocker::ReadUnlock() } // else: we are probably going to be destroyed } -// IsReadLocked -// -// Returns whether or not the calling thread owns a read lock or, if -// orWriteLock is true, at least a write lock. + +/** Returns whether or not the calling thread owns a read lock or, if + * orWriteLock is true, at least a write lock. + */ + bool RWLocker::IsReadLocked(bool orWriteLock) const { @@ -166,10 +166,13 @@ RWLocker::WriteUnlock() if (fWriterReaderCount > 0) { // We still own read locks. _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 // at the mutex semaphore. We need to wake it up. if (fReaderCount > 0) _ReleaseBenaphore(fMutex); + fReaderCount += fWriterReaderCount; fWriterReaderCount = 0; } else { @@ -183,9 +186,9 @@ RWLocker::WriteUnlock() } // 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 RWLocker::IsWriteLocked() const { @@ -193,8 +196,7 @@ RWLocker::IsWriteLocked() const } // make_sem_name -static -void +static void make_sem_name(char *buffer, const char *name, const char *suffix) { if (!name) @@ -252,8 +254,11 @@ RWLocker::_ReadLock(bigtime_t timeout) locked = true; } _ReleaseBenaphore(fLock); - } else // failed to lock the data + } 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); @@ -262,11 +267,18 @@ RWLocker::_ReadLock(bigtime_t timeout) bool firstReader = false; if (++fReaderCount == 1) { // We are the first reader. - _NewReadLockInfo(thread); firstReader = true; - } else - _NewReadLockInfo(thread); + } + + int32 index = _NewReadLockInfo(thread); _ReleaseBenaphore(fLock); + + if (index < 0) { + // creating a ReadLockInfo object failed + _ReleaseBenaphore(fQueue); + return B_NO_MEMORY; + } + // The first reader needs to lock the mutex. if (firstReader) { error = _AcquireBenaphore(fMutex, timeout); @@ -399,6 +411,7 @@ RWLocker::_WriteLock(bigtime_t timeout) break; } } + // Second step: acquire the mutex benaphore. if (!locked && error == B_OK) { error = _AcquireBenaphore(fMutex, timeout); @@ -440,14 +453,19 @@ RWLocker::_AddReadLockInfo(ReadLockInfo* info) 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. + +/** Create a new read lock info for the supplied thread and add it to + * the list. Returns the index of the info, or -1 to indicate an out + * of memory situation. + */ + int32 RWLocker::_NewReadLockInfo(thread_id thread, int32 count) { ReadLockInfo* info = new(nothrow) ReadLockInfo; + if (info == NULL) + return -1; + info->reader = thread; info->count = count; return _AddReadLockInfo(info);