diff --git a/headers/private/kernel/disk_device_manager/KDiskDevice.h b/headers/private/kernel/disk_device_manager/KDiskDevice.h index ddb5cfcf3a..799e7f038d 100644 --- a/headers/private/kernel/disk_device_manager/KDiskDevice.h +++ b/headers/private/kernel/disk_device_manager/KDiskDevice.h @@ -5,10 +5,12 @@ #ifndef _K_DISK_DEVICE_H #define _K_DISK_DEVICE_H + #include +#include + #include "KPartition.h" -#include "RWLocker.h" namespace BPrivate { @@ -36,10 +38,8 @@ public: // manager lock owners can be sure, that it won't change. bool ReadLock(); void ReadUnlock(); - bool IsReadLocked(bool orWriteLocked = true); bool WriteLock(); void WriteUnlock(); - bool IsWriteLocked(); virtual void SetID(partition_id id); @@ -92,7 +92,7 @@ private: void _UpdateDeviceFlags(); disk_device_data fDeviceData; - RWLocker fLocker; + rw_lock fLocker; int fFD; status_t fMediaStatus; }; diff --git a/headers/private/kernel/disk_device_manager/KDiskDeviceManager.h b/headers/private/kernel/disk_device_manager/KDiskDeviceManager.h index d604828007..1727b4d319 100644 --- a/headers/private/kernel/disk_device_manager/KDiskDeviceManager.h +++ b/headers/private/kernel/disk_device_manager/KDiskDeviceManager.h @@ -133,7 +133,7 @@ private: void _NotifyDeviceEvent(KDiskDevice* device, int32 event, uint32 mask); - BLocker fLock; + recursive_lock fLock; DeviceMap *fDevices; PartitionMap *fPartitions; DiskSystemMap *fDiskSystems; diff --git a/headers/private/kernel/disk_device_manager/RWLocker.h b/headers/private/kernel/disk_device_manager/RWLocker.h deleted file mode 100644 index ccaef57a48..0000000000 --- a/headers/private/kernel/disk_device_manager/RWLocker.h +++ /dev/null @@ -1,131 +0,0 @@ -// RWLocker.h -// -// 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 - -#include - -class RWLocker { - public: - RWLocker(); - RWLocker(const char* name); - virtual ~RWLocker(); - - status_t InitCheck() const; - - bool ReadLock(); - status_t ReadLockWithTimeout(bigtime_t timeout); - void ReadUnlock(); - bool IsReadLocked(bool orWriteLock = true) 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: - status_t _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 = B_INFINITE_TIMEOUT); - static void _ReleaseBenaphore(Benaphore& benaphore); - - private: - mutable Benaphore fLock; // data lock - Benaphore fMutex; // critical code mutex - Benaphore fQueue; // queueing semaphore - int32 fReaderCount; // total count... - int32 fWriterCount; // total count... - Vector fReadLockInfos; - thread_id fWriter; // current write lock - // owner - int32 fWriterWriterCount; // write lock owner - // count - int32 fWriterReaderCount; // writer read lock - // owner count -}; - -#endif // RW_LOCKER_H diff --git a/src/system/kernel/disk_device_manager/Jamfile b/src/system/kernel/disk_device_manager/Jamfile index 3647afded3..c522e9aa10 100644 --- a/src/system/kernel/disk_device_manager/Jamfile +++ b/src/system/kernel/disk_device_manager/Jamfile @@ -27,10 +27,6 @@ KernelMergeObject kernel_disk_device_manager.o : KPartitionVisitor.cpp UserDataWriter.cpp - # utilities - Locker.cpp - RWLocker.cpp - # disk device types DiskDeviceTypes.cpp diff --git a/src/system/kernel/disk_device_manager/KDiskDevice.cpp b/src/system/kernel/disk_device_manager/KDiskDevice.cpp index 3a99dc9bbf..4f1c74a066 100644 --- a/src/system/kernel/disk_device_manager/KDiskDevice.cpp +++ b/src/system/kernel/disk_device_manager/KDiskDevice.cpp @@ -23,26 +23,27 @@ #define DBG(x) x #define OUT dprintf -// constructor + KDiskDevice::KDiskDevice(partition_id id) - : KPartition(id), - fDeviceData(), - fLocker("diskdevice"), - fFD(-1), - fMediaStatus(B_ERROR) + : + KPartition(id), + fDeviceData(), + fLocker(RW_LOCK_INITIALIZER("disk device")), + fFD(-1), + fMediaStatus(B_ERROR) { Unset(); fDevice = this; fPublishedName = (char*)"raw"; } -// destructor + KDiskDevice::~KDiskDevice() { Unset(); } -// SetTo + status_t KDiskDevice::SetTo(const char *path) { @@ -84,7 +85,7 @@ KDiskDevice::SetTo(const char *path) return B_OK; } -// Unset + void KDiskDevice::Unset() { @@ -102,57 +103,42 @@ KDiskDevice::Unset() _ResetGeometry(); } -// InitCheck + status_t KDiskDevice::InitCheck() const { - return fLocker.InitCheck(); + return B_OK; } -// ReadLock + bool KDiskDevice::ReadLock() { - return fLocker.ReadLock(); + return rw_lock_read_lock(&fLocker) == B_OK; } -// ReadUnlock + void KDiskDevice::ReadUnlock() { - fLocker.ReadUnlock(); + rw_lock_read_unlock(&fLocker); } -// IsReadLocked -bool -KDiskDevice::IsReadLocked(bool orWriteLocked) -{ - return fLocker.IsReadLocked(orWriteLocked); -} -// WriteLock bool KDiskDevice::WriteLock() { - return fLocker.WriteLock(); + return rw_lock_write_lock(&fLocker) == B_OK; } -// WriteUnlock + void KDiskDevice::WriteUnlock() { - fLocker.WriteUnlock(); -} - -// IsWriteLocked -bool -KDiskDevice::IsWriteLocked() -{ - return fLocker.IsWriteLocked(); + rw_lock_write_unlock(&fLocker); } -// SetID void KDiskDevice::SetID(partition_id id) { @@ -160,7 +146,7 @@ KDiskDevice::SetID(partition_id id) fDeviceData.id = id; } -// PublishDevice + status_t KDiskDevice::PublishDevice() { diff --git a/src/system/kernel/disk_device_manager/KDiskDeviceManager.cpp b/src/system/kernel/disk_device_manager/KDiskDeviceManager.cpp index 531d6e2fcf..ea4ca690b6 100644 --- a/src/system/kernel/disk_device_manager/KDiskDeviceManager.cpp +++ b/src/system/kernel/disk_device_manager/KDiskDeviceManager.cpp @@ -239,7 +239,7 @@ public: KDiskDeviceManager::KDiskDeviceManager() : - fLock("disk device manager"), + fLock(RECURSIVE_LOCK_INITIALIZER("disk device manager")), fDevices(new(nothrow) DeviceMap), fPartitions(new(nothrow) PartitionMap), fDiskSystems(new(nothrow) DiskSystemMap), @@ -324,7 +324,7 @@ KDiskDeviceManager::InitCheck() const || fObsoletePartitions == NULL || fNotifications == NULL) return B_NO_MEMORY; - return fLock.Sem() >= 0 ? B_OK : fLock.Sem(); + return B_OK; } @@ -366,14 +366,14 @@ KDiskDeviceManager::Default() bool KDiskDeviceManager::Lock() { - return fLock.Lock(); + return recursive_lock_lock(&fLock) == B_OK; } void KDiskDeviceManager::Unlock() { - fLock.Unlock(); + recursive_lock_unlock(&fLock); } diff --git a/src/system/kernel/disk_device_manager/Locker.cpp b/src/system/kernel/disk_device_manager/Locker.cpp deleted file mode 100644 index 34d6cb312d..0000000000 --- a/src/system/kernel/disk_device_manager/Locker.cpp +++ /dev/null @@ -1,305 +0,0 @@ -// -// $Id: Locker.cpp,v 1.2 2003/10/25 13:24:59 wkornew Exp $ -// -// This file contains the OpenBeOS implementation of BLocker. -// - - -#include "Locker.h" -#include -#include - -#ifdef _KERNEL_MODE - #include -#endif - - -#ifdef USE_OPENBEOS_NAMESPACE -namespace OpenBeOS { -#endif - - -// -// Data Member Documentation: -// -// The "fBenaphoreCount" member is set to 1 if the BLocker style is -// semaphore. If the style is benaphore, it is initialized to 0 and -// is incremented atomically when it is acquired, decremented when it -// is released. By setting the benaphore count to 1 when the style is -// semaphore, the benaphore effectively becomes a semaphore. I was able -// to determine this is what Be's implementation does by testing the -// result of the CountLockRequests() member. -// -// The "fSemaphoreID" member holds the sem_id returned from create_sem() -// when the BLocker is constructed. It is used to acquire and release -// the lock regardless of the lock style (semaphore or benaphore). -// -// The "fLockOwner" member holds the thread_id of the thread which -// currently holds the lock. If no thread holds the lock, it is set to -// B_ERROR. -// -// The "fRecursiveCount" member holds a count of the number of times the -// thread holding the lock has acquired the lock without a matching unlock. -// It is basically the number of times the thread must call Unlock() before -// the lock can be acquired by a different thread. -// - - -// -// Constructors: -// -// All constructors just pass their arguments to InitLocker(). Note that -// the default for "name" is "some BLocker" and "benaphore_style" is true. -// - -BLocker::BLocker() -{ - InitLocker("some BLocker", true); -} - - -BLocker::BLocker(const char *name) -{ - InitLocker(name, true); -} - - -BLocker::BLocker(bool benaphore_style) -{ - InitLocker("some BLocker", benaphore_style); -} - - -BLocker::BLocker(const char *name, - bool benaphore_style) -{ - InitLocker(name, benaphore_style); -} - - -// -// This constructor is not documented. The final argument is ignored for -// now. In Be's headers, its called "for_IPC". DO NOT USE THIS -// CONSTRUCTOR! -// -BLocker::BLocker(const char *name, - bool benaphore_style, - bool) -{ - InitLocker(name, benaphore_style); -} - - -// -// The destructor just deletes the semaphore. By deleting the semaphore, -// any threads waiting to acquire the BLocker will be unblocked. -// -BLocker::~BLocker() -{ - delete_sem(fSemaphoreID); -} - - -bool -BLocker::Lock(void) -{ - status_t result; - - return (AcquireLock(B_INFINITE_TIMEOUT, &result)); -} - - -status_t -BLocker::LockWithTimeout(bigtime_t timeout) -{ - status_t result; - - AcquireLock(timeout, &result); - return result; -} - - - -void -BLocker::Unlock(void) -{ - // If the thread currently holds the lockdecrement - if (IsLocked()) { - - // Decrement the number of outstanding locks this thread holds - // on this BLocker. - fRecursiveCount--; - - // If the recursive count is now at 0, that means the BLocker has - // been released by the thread. - if (fRecursiveCount == 0) { - - // The BLocker is no longer owned by any thread. - fLockOwner = B_ERROR; - - // Decrement the benaphore count and store the undecremented - // value in oldBenaphoreCount. - int32 oldBenaphoreCount = atomic_add(&fBenaphoreCount, -1); - - // If the oldBenaphoreCount is greater than 1, then there is - // at lease one thread waiting for the lock in the case of a - // benaphore. - if (oldBenaphoreCount > 1) { - - // Since there are threads waiting for the lock, it must - // be released. Note, the old benaphore count will always be - // greater than 1 for a semaphore so the release is always done. - release_sem(fSemaphoreID); - } - } - } -} - - -thread_id -BLocker::LockingThread(void) const -{ - return fLockOwner; -} - - -bool -BLocker::IsLocked(void) const -{ - // This member returns true if the calling thread holds the lock. - // The easiest way to determine this is to compare the result of - // find_thread() to the fLockOwner. - return (find_thread(NULL) == fLockOwner); -} - - -int32 -BLocker::CountLocks(void) const -{ - return fRecursiveCount; -} - - -int32 -BLocker::CountLockRequests(void) const -{ - return fBenaphoreCount; -} - - -sem_id -BLocker::Sem(void) const -{ - return fSemaphoreID; -} - - -void -BLocker::InitLocker(const char *name, - bool benaphore) -{ - if (benaphore) { - // Because this is a benaphore, initialize the benaphore count and - // create the semaphore. Because this is a benaphore, the semaphore - // count starts at 0 (ie acquired). - fBenaphoreCount = 0; - fSemaphoreID = create_sem(0, name); - } else { - // Because this is a semaphore, initialize the benaphore count to -1 - // and create the semaphore. Because this is semaphore style, the - // semaphore count starts at 1 so that one thread can acquire it and - // the next thread to acquire it will block. - fBenaphoreCount = 1; - fSemaphoreID = create_sem(1, name); - } - -#ifdef _KERNEL_MODE - set_sem_owner(fSemaphoreID, B_SYSTEM_TEAM); -#endif - - // The lock is currently not acquired so there is no owner. - fLockOwner = B_ERROR; - - // The lock is currently not acquired so the recursive count is zero. - fRecursiveCount = 0; -} - - -bool -BLocker::AcquireLock(bigtime_t timeout, - status_t *error) -{ - // By default, return no error. - *error = B_NO_ERROR; - - // Only try to acquire the lock if the thread doesn't already own it. - if (!IsLocked()) { - - // Increment the benaphore count and test to see if it was already greater - // than 0. If it is greater than 0, then some thread already has the - // benaphore or the style is a semaphore. Either way, we need to acquire - // the semaphore in this case. - int32 oldBenaphoreCount = atomic_add(&fBenaphoreCount, 1); - if (oldBenaphoreCount > 0) { - - *error = acquire_sem_etc(fSemaphoreID, 1, B_RELATIVE_TIMEOUT, - timeout); - // Note, if the lock here does time out, the benaphore count - // is not decremented. By doing this, the benaphore count will - // never go back to zero. This means that the locking essentially - // changes to semaphore style if this was a benaphore. - // - // Doing the decrement of the benaphore count when the acquisition - // fails is a risky thing to do. If you decrement the counter at - // the same time the thread which holds the benaphore does an - // Unlock(), there is serious risk of a race condition. - // - // If the Unlock() sees a positive count and releases the semaphore - // and then the timed out thread decrements the count to 0, there - // is no one to take the semaphore. The next two threads will be - // able to acquire the benaphore at the same time! The first will - // increment the counter and acquire the lock. The second will - // acquire the semaphore and therefore the lock. Not good. - // - // This has been discussed on the becodetalk mailing list and - // Trey from Be had this to say: - // - // I looked at the LockWithTimeout() code, and it does not have - // _this_ (ie the race condition) problem. It circumvents it by - // NOT doing the atomic_add(&count, -1) if the semaphore - // acquisition fails. This means that if a - // BLocker::LockWithTimeout() times out, all other Lock*() attempts - // turn into guaranteed semaphore grabs, _with_ the overhead of a - // (now) useless atomic_add(). - // - // Given Trey's comments, it looks like Be took the same approach - // I did. The output of CountLockRequests() of Be's implementation - // confirms Trey's comments also. - // - // Finally some thoughts for the future with this code: - // - If 2^31 timeouts occur on a 32-bit machine (ie today), - // the benaphore count will wrap to a negative number. This - // would have unknown consequences on the ability of the BLocker - // to continue to function. - // - } - } - - // If the lock has successfully been acquired. - if (*error == B_NO_ERROR) { - - // Set the lock owner to this thread and increment the recursive count - // by one. The recursive count is incremented because one more Unlock() - // is now required to release the lock (ie, 0 => 1, 1 => 2 etc). - fLockOwner = find_thread(NULL); - fRecursiveCount++; - } - - // Return true if the lock has been acquired. - return (*error == B_NO_ERROR); -} - - -#ifdef USE_OPENBEOS_NAMESPACE -} -#endif diff --git a/src/system/kernel/disk_device_manager/Locker.h b/src/system/kernel/disk_device_manager/Locker.h deleted file mode 100644 index 306c40bb6d..0000000000 --- a/src/system/kernel/disk_device_manager/Locker.h +++ /dev/null @@ -1,63 +0,0 @@ -// -// $Id: Locker.h,v 1.1 2003/06/10 22:29:52 bonefish Exp $ -// -// This is the BLocker interface for OpenBeOS. It has been created to -// be source and binary compatible with the BeOS version of BLocker. -// -// bonefish: Removed virtual from destructor. - - -#ifndef _OPENBEOS_LOCKER_H -#define _OPENBEOS_LOCKER_H - - -#include -#include - - -#ifdef USE_OPENBEOS_NAMESPACE -namespace OpenBeOS { -#endif - -class BLocker { -public: - BLocker(); - BLocker(const char *name); - BLocker(bool benaphore_style); - BLocker(const char *name, bool benaphore_style); - - // The following constructor is not documented in the BeBook - // and is only listed here to ensure binary compatibility. - // DO NOT USE THIS CONSTRUCTOR! - BLocker(const char *name, bool benaphore_style, bool); - - ~BLocker(); - - bool Lock(void); - status_t LockWithTimeout(bigtime_t timeout); - void Unlock(void); - - thread_id LockingThread(void) const; - bool IsLocked(void) const; - int32 CountLocks(void) const; - int32 CountLockRequests(void) const; - sem_id Sem(void) const; - -private: - void InitLocker(const char *name, bool benaphore_style); - bool AcquireLock(bigtime_t timeout, status_t *error); - - int32 fBenaphoreCount; - sem_id fSemaphoreID; - thread_id fLockOwner; - int32 fRecursiveCount; - - // Reserved space for future changes to BLocker - int32 fReservedSpace[4]; -}; - -#ifdef USE_OPENBEOS_NAMESPACE -} -#endif - -#endif // _OPENBEOS_LOCKER_H diff --git a/src/system/kernel/disk_device_manager/RWLocker.cpp b/src/system/kernel/disk_device_manager/RWLocker.cpp deleted file mode 100644 index 37cadaa55a..0000000000 --- a/src/system/kernel/disk_device_manager/RWLocker.cpp +++ /dev/null @@ -1,525 +0,0 @@ -// RWLocker.cpp - -#include - -#include "RWLocker.h" - -using namespace std; - -// info about a read lock owner -struct RWLocker::ReadLockInfo { - thread_id reader; - int32 count; -}; - - -// constructor -RWLocker::RWLocker() - : - fReaderCount(0), - fWriterCount(0), - fReadLockInfos(8), - fWriter(B_ERROR), - fWriterWriterCount(0), - fWriterReaderCount(0) -{ - _Init(NULL); -} - -// constructor -RWLocker::RWLocker(const char* name) - : - fReaderCount(0), - fWriterCount(0), - fReadLockInfos(8), - fWriter(B_ERROR), - fWriterWriterCount(0), - fWriterReaderCount(0) -{ - _Init(name); -} - -// destructor -RWLocker::~RWLocker() -{ - _AcquireBenaphore(fLock); - delete_sem(fMutex.semaphore); - delete_sem(fQueue.semaphore); - for (int32 i = 0; ReadLockInfo* info = _ReadLockInfoAt(i); i++) { - delete info; - } - - delete_sem(fLock.semaphore); -} - -// InitCheck -status_t -RWLocker::InitCheck() const -{ - if (fLock.semaphore < 0) - return fLock.semaphore; - if (fMutex.semaphore < 0) - return fMutex.semaphore; - if (fQueue.semaphore < 0) - return fQueue.semaphore; - - return B_OK; -} - -// 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 (_AcquireBenaphore(fLock) == B_OK) { - 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 - } - _ReleaseBenaphore(fLock); - } // else: we are probably going to be destroyed -} - - -/** 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 -{ - bool result = false; - if (_AcquireBenaphore(fLock) == B_OK) { - thread_id thread = find_thread(NULL); - result = ((orWriteLock && thread == fWriter) || _IndexOf(thread) >= 0); - _ReleaseBenaphore(fLock); - } - 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 (_AcquireBenaphore(fLock) == B_OK) { - 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); - // 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 { - // We don't own any read locks. So we have to release the - // mutex benaphore. - _ReleaseBenaphore(fMutex); - } - } - } // else: error: unmatched WriteUnlock() - _ReleaseBenaphore(fLock); - } // else: We're probably going to die. -} - - -/** Returns whether or not the calling thread owns a write lock. */ - -bool -RWLocker::IsWriteLocked() const -{ - return (fWriter == find_thread(NULL)); -} - -// make_sem_name -static void -make_sem_name(char *buffer, const char *name, const char *suffix) -{ - if (!name) - name = "unnamed_rwlocker"; - int32 nameLen = strlen(name); - int32 suffixLen = strlen(suffix); - if (suffixLen >= B_OS_NAME_LENGTH) - suffixLen = B_OS_NAME_LENGTH - 1; - if (nameLen + suffixLen >= B_OS_NAME_LENGTH) - nameLen = B_OS_NAME_LENGTH - suffixLen - 1; - memcpy(buffer, name, nameLen); - memcpy(buffer + nameLen, suffix, suffixLen); - buffer[nameLen + suffixLen] = '\0'; -} - -// _Init -status_t -RWLocker::_Init(const char* name) -{ - // init the data lock benaphore - fLock.semaphore = create_sem(0, name); - fLock.counter = 0; - // init the mutex benaphore - char semName[B_OS_NAME_LENGTH]; - make_sem_name(semName, name, "_mutex"); - fMutex.semaphore = create_sem(0, semName); - fMutex.counter = 0; - // init the queueing benaphore - make_sem_name(semName, name, "_queue"); - fQueue.semaphore = create_sem(0, semName); - fQueue.counter = 0; - return InitCheck(); -} - -// _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 (_AcquireBenaphore(fLock) == B_OK) { - // 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; - } - _ReleaseBenaphore(fLock); - } 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 (_AcquireBenaphore(fLock) == B_OK) { - bool firstReader = false; - if (++fReaderCount == 1) { - // We are the first reader. - firstReader = true; - } - - 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); - switch (error) { - case B_OK: - // fine - break; - case B_TIMED_OUT: { - // clean up - if (_AcquireBenaphore(fLock) == B_OK) { - _DeleteReadLockInfo(_IndexOf(thread)); - fReaderCount--; - _ReleaseBenaphore(fLock); - } - 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 (_AcquireBenaphore(fLock) == B_OK) { - 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; - } - } - _ReleaseBenaphore(fLock); - // 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 (_AcquireBenaphore(fLock) == B_OK) { - fWriterCount--; - _ReleaseBenaphore(fLock); - } // 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 (_AcquireBenaphore(fLock) == B_OK) { - fWriterCount--; - _ReleaseBenaphore(fLock); - } // 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.Count(); - fReadLockInfos.Insert(info, index); - return index; -} - - -/** 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); -} - -// _DeleteReadLockInfo -void -RWLocker::_DeleteReadLockInfo(int32 index) -{ - if (index >= 0 && index < fReadLockInfos.Count()) { - ReadLockInfo* info = fReadLockInfos.ElementAt(index); - fReadLockInfos.Erase(index); - delete info; - } -} - -// _ReadLockInfoAt -RWLocker::ReadLockInfo* -RWLocker::_ReadLockInfoAt(int32 index) const -{ - if (index >= 0 && index < fReadLockInfos.Count()) - return fReadLockInfos.ElementAt(index); - return NULL; -} - -// _IndexOf -int32 -RWLocker::_IndexOf(thread_id thread) const -{ - int32 count = fReadLockInfos.Count(); - 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); -} - diff --git a/src/system/kernel/disk_device_manager/disk_device_manager.cpp b/src/system/kernel/disk_device_manager/disk_device_manager.cpp index 5e4e61bc49..c4814ab5b8 100644 --- a/src/system/kernel/disk_device_manager/disk_device_manager.cpp +++ b/src/system/kernel/disk_device_manager/disk_device_manager.cpp @@ -39,11 +39,9 @@ write_unlock_disk_device(partition_id partitionID) { KDiskDeviceManager* manager = KDiskDeviceManager::Default(); if (KDiskDevice* device = manager->RegisterDevice(partitionID, false)) { - bool isLocked = device->IsWriteLocked(); - if (isLocked) { - device->WriteUnlock(); - device->Unregister(); - } + device->WriteUnlock(); + device->Unregister(); + device->Unregister(); } } @@ -71,11 +69,9 @@ read_unlock_disk_device(partition_id partitionID) { KDiskDeviceManager* manager = KDiskDeviceManager::Default(); if (KDiskDevice* device = manager->RegisterDevice(partitionID, false)) { - bool isLocked = device->IsReadLocked(false); - if (isLocked) { - device->ReadUnlock(); - device->Unregister(); - } + device->ReadUnlock(); + device->Unregister(); + device->Unregister(); } } diff --git a/src/system/kernel/messaging/MessagingService.cpp b/src/system/kernel/messaging/MessagingService.cpp index 02b17ed3fb..8f7f5d68fc 100644 --- a/src/system/kernel/messaging/MessagingService.cpp +++ b/src/system/kernel/messaging/MessagingService.cpp @@ -1,9 +1,11 @@ -/* +/* * Copyright 2005-2008, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ -// kernel-side implementation of the messaging service + +//! kernel-side implementation of the messaging service + #include @@ -33,13 +35,11 @@ static const int32 kMessagingAreaSize = B_PAGE_SIZE * 4; // #pragma mark - MessagingArea -// constructor MessagingArea::MessagingArea() { } -// destructor MessagingArea::~MessagingArea() { if (fID >= 0) @@ -47,7 +47,6 @@ MessagingArea::~MessagingArea() } -// Create MessagingArea * MessagingArea::Create(sem_id lockSem, sem_id counterSem) { @@ -76,7 +75,6 @@ MessagingArea::Create(sem_id lockSem, sem_id counterSem) } -// InitHeader void MessagingArea::InitHeader() { @@ -90,7 +88,6 @@ MessagingArea::InitHeader() } -// CheckCommandSize bool MessagingArea::CheckCommandSize(int32 dataSize) { @@ -101,7 +98,6 @@ MessagingArea::CheckCommandSize(int32 dataSize) } -// Lock bool MessagingArea::Lock() { @@ -113,7 +109,6 @@ MessagingArea::Lock() } -// Unlock void MessagingArea::Unlock() { @@ -122,7 +117,6 @@ MessagingArea::Unlock() } -// ID area_id MessagingArea::ID() const { @@ -130,7 +124,6 @@ MessagingArea::ID() const } -// Size int32 MessagingArea::Size() const { @@ -138,7 +131,6 @@ MessagingArea::Size() const } -// Empty bool MessagingArea::IsEmpty() const { @@ -146,7 +138,6 @@ MessagingArea::IsEmpty() const } -// AllocateCommand void * MessagingArea::AllocateCommand(uint32 commandWhat, int32 dataSize, bool &wasEmpty) @@ -218,7 +209,6 @@ MessagingArea::AllocateCommand(uint32 commandWhat, int32 dataSize, } -// CommitCommand void MessagingArea::CommitCommand() { @@ -227,7 +217,6 @@ MessagingArea::CommitCommand() } -// SetNextArea void MessagingArea::SetNextArea(MessagingArea *area) { @@ -236,7 +225,6 @@ MessagingArea::SetNextArea(MessagingArea *area) } -// NextArea MessagingArea * MessagingArea::NextArea() const { @@ -244,7 +232,6 @@ MessagingArea::NextArea() const } -// _CheckCommand messaging_command * MessagingArea::_CheckCommand(int32 offset, int32 &size) { @@ -271,16 +258,15 @@ MessagingArea::_CheckCommand(int32 offset, int32 &size) // #pragma mark - MessagingService -// constructor MessagingService::MessagingService() - : fLock("messaging service"), - fFirstArea(NULL), - fLastArea(NULL) + : + fLock(RECURSIVE_LOCK_INITIALIZER("messaging service")), + fFirstArea(NULL), + fLastArea(NULL) { } -// destructor MessagingService::~MessagingService() { // Should actually never be called. Once created the service stays till the @@ -288,33 +274,27 @@ MessagingService::~MessagingService() } -// InitCheck status_t MessagingService::InitCheck() const { - if (fLock.Sem() < 0) - return fLock.Sem(); return B_OK; } -// Lock bool MessagingService::Lock() { - return fLock.Lock(); + return recursive_lock_lock(&fLock) == B_OK; } -// Unlock void MessagingService::Unlock() { - fLock.Unlock(); + recursive_lock_unlock(&fLock); } -// RegisterService status_t MessagingService::RegisterService(sem_id lockSem, sem_id counterSem, area_id &areaID) @@ -362,7 +342,6 @@ MessagingService::RegisterService(sem_id lockSem, sem_id counterSem, } -// UnregisterService status_t MessagingService::UnregisterService() { @@ -392,7 +371,6 @@ MessagingService::UnregisterService() } -// SendMessage status_t MessagingService::SendMessage(const void *message, int32 messageSize, const messaging_target *targets, int32 targetCount) @@ -436,7 +414,6 @@ PRINT((" Allocated space for send message command: area: %p, data: %p, " } -// _AllocateCommand status_t MessagingService::_AllocateCommand(int32 commandWhat, int32 size, MessagingArea *&area, void *&data, bool &wasEmpty) @@ -513,7 +490,6 @@ MessagingService::_AllocateCommand(int32 commandWhat, int32 size, // #pragma mark - kernel private -// send_message status_t send_message(const void *message, int32 messageSize, const messaging_target *targets, int32 targetCount) @@ -534,7 +510,6 @@ send_message(const void *message, int32 messageSize, } -// send_message status_t send_message(const KMessage *message, const messaging_target *targets, int32 targetCount) @@ -547,7 +522,6 @@ send_message(const KMessage *message, const messaging_target *targets, } -// init_messaging_service status_t init_messaging_service() { @@ -573,7 +547,6 @@ init_messaging_service() // #pragma mark - syscalls -// _user_register_messaging_service /** \brief Called by the userland server to register itself as a messaging service for the kernel. \param lockingSem A semaphore used for locking the shared data. Semaphore @@ -605,7 +578,6 @@ _user_register_messaging_service(sem_id lockSem, sem_id counterSem) } -// _user_unregister_messaging_service status_t _user_unregister_messaging_service() { diff --git a/src/system/kernel/messaging/MessagingService.h b/src/system/kernel/messaging/MessagingService.h index 0e913bc764..48786863f5 100644 --- a/src/system/kernel/messaging/MessagingService.h +++ b/src/system/kernel/messaging/MessagingService.h @@ -1,16 +1,18 @@ -/* +/* * Copyright 2005, Ingo Weinhold, bonefish@users.sf.net. All rights reserved. * Distributed under the terms of the MIT License. */ - -// kernel-side implementation-private definitions for the messaging service - #ifndef MESSAGING_SERVICE_H #define MESSAGING_SERVICE_H + +//! kernel-side implementation-private definitions for the messaging service + + #include -#include "Locker.h" +#include + namespace BPrivate { @@ -73,7 +75,7 @@ private: status_t _AllocateCommand(int32 commandWhat, int32 size, MessagingArea *&area, void *&data, bool &wasEmpty); - BLocker fLock; + recursive_lock fLock; team_id fServerTeam; sem_id fLockSem; sem_id fCounterSem;