⛏️ index : haiku.git

/*
 * Copyright 2005-2009, Haiku, Inc. All Rights Reserved.
 * Distributed under the terms of the MIT license.
 *
 * Copyright 1999, Be Incorporated. All Rights Reserved.
 * This file may be used under the terms of the Be Sample Code License.
 */
#ifndef MULTI_LOCKER_H
#define MULTI_LOCKER_H


/*! multiple-reader single-writer locking class

	IMPORTANT:
	 * nested read locks are not supported
	 * a reader becoming the write is not supported
	 * nested write locks are supported
	 * a writer can do read locks, even nested ones
	 * in case of problems, #define DEBUG 1 in the .cpp
*/


#include <OS.h>
#include <locks.h>


#define MULTI_LOCKER_TIMING	0
#if DEBUG
#	include <assert.h>
#	define MULTI_LOCKER_DEBUG	DEBUG
#endif

#if MULTI_LOCKER_DEBUG
#	define ASSERT_MULTI_LOCKED(x) assert((x).IsWriteLocked() || (x).IsReadLocked())
#	define ASSERT_MULTI_READ_LOCKED(x) assert((x).IsReadLocked())
#	define ASSERT_MULTI_WRITE_LOCKED(x) assert((x).IsWriteLocked())
#else
#	define MULTI_LOCKER_DEBUG	0
#	define ASSERT_MULTI_LOCKED(x) ;
#	define ASSERT_MULTI_READ_LOCKED(x) ;
#	define ASSERT_MULTI_WRITE_LOCKED(x) ;
#endif


class MultiLocker {
public:
								MultiLocker(const char* baseName);
	virtual						~MultiLocker();

			status_t			InitCheck();

			// locking for reading or writing
			bool				ReadLock();
			bool				WriteLock();

			// unlocking after reading or writing
			bool				ReadUnlock();
			bool				WriteUnlock();

			// does the current thread hold a write lock?
			bool				IsWriteLocked() const;

#if MULTI_LOCKER_DEBUG
			// in DEBUG mode returns whether the lock is held
			// in non-debug mode returns true
			bool				IsReadLocked() const;
#endif

private:
								MultiLocker();
								MultiLocker(const MultiLocker& other);
			MultiLocker&		operator=(const MultiLocker& other);
									// not implemented

#if !MULTI_LOCKER_DEBUG
			rw_lock				fLock;
#else
			// functions for managing the DEBUG reader array
			void				_RegisterThread();
			void				_UnregisterThread();

			sem_id				fLock;
			int32*				fDebugArray;
			int32				fMaxThreads;
			int32				fWriterNest;
			thread_id			fWriterThread;
#endif	// MULTI_LOCKER_DEBUG

			status_t			fInit;

#if MULTI_LOCKER_TIMING
			uint32 				rl_count;
			bigtime_t 			rl_time;
			uint32 				ru_count;
			bigtime_t	 		ru_time;
			uint32				wl_count;
			bigtime_t			wl_time;
			uint32				wu_count;
			bigtime_t			wu_time;
			uint32				islock_count;
			bigtime_t			islock_time;
#endif
};


class AutoWriteLocker {
public:
	AutoWriteLocker(MultiLocker* lock)
		:
		fLock(*lock)
	{
		fLocked = fLock.WriteLock();
	}

	AutoWriteLocker(MultiLocker& lock)
		:
		fLock(lock)
	{
		fLocked = fLock.WriteLock();
	}

	~AutoWriteLocker()
	{
		if (fLocked)
			fLock.WriteUnlock();
	}

	bool IsLocked() const
	{
		return fLock.IsWriteLocked();
	}

	void Unlock()
	{
		if (fLocked) {
			fLock.WriteUnlock();
			fLocked = false;
		}
	}

private:
 	MultiLocker&	fLock;
	bool			fLocked;
};


class AutoReadLocker {
public:
	AutoReadLocker(MultiLocker* lock)
		:
		fLock(*lock)
	{
		fLocked = fLock.ReadLock();
	}

	AutoReadLocker(MultiLocker& lock)
		:
		fLock(lock)
	{
		fLocked = fLock.ReadLock();
	}

	~AutoReadLocker()
	{
		Unlock();
	}

	void Unlock()
	{
		if (fLocked) {
			fLock.ReadUnlock();
			fLocked = false;
		}
	}

private:
	MultiLocker&	fLock;
	bool			fLocked;
};

#endif	// MULTI_LOCKER_H