Moved to headers/private/kernel/disk_device_manager, since it is included by KDiskDevice.h.
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@9540 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
// 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 <OS.h>
|
||||
|
||||
#include <Vector.h>
|
||||
|
||||
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<ReadLockInfo*> 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
|
||||
Reference in New Issue
Block a user