master chld/haikuprg / decor / MacDecorator / includes / MultiLocker.h
  1/*
  2 * Copyright 2005-2009, Haiku, Inc. All Rights Reserved.
  3 * Distributed under the terms of the MIT license.
  4 *
  5 * Copyright 1999, Be Incorporated. All Rights Reserved.
  6 * This file may be used under the terms of the Be Sample Code License.
  7 */
  8#ifndef MULTI_LOCKER_H
  9#define MULTI_LOCKER_H
 10
 11
 12/*! multiple-reader single-writer locking class
 13
 14	IMPORTANT:
 15	 * nested read locks are not supported
 16	 * a reader becoming the write is not supported
 17	 * nested write locks are supported
 18	 * a writer can do read locks, even nested ones
 19	 * in case of problems, #define DEBUG 1 in the .cpp
 20*/
 21
 22
 23#include <OS.h>
 24#include <locks.h>
 25
 26
 27#define MULTI_LOCKER_TIMING	0
 28#if DEBUG
 29#	include <assert.h>
 30#	define MULTI_LOCKER_DEBUG	DEBUG
 31#endif
 32
 33#if MULTI_LOCKER_DEBUG
 34#	define ASSERT_MULTI_LOCKED(x) assert((x).IsWriteLocked() || (x).IsReadLocked())
 35#	define ASSERT_MULTI_READ_LOCKED(x) assert((x).IsReadLocked())
 36#	define ASSERT_MULTI_WRITE_LOCKED(x) assert((x).IsWriteLocked())
 37#else
 38#	define MULTI_LOCKER_DEBUG	0
 39#	define ASSERT_MULTI_LOCKED(x) ;
 40#	define ASSERT_MULTI_READ_LOCKED(x) ;
 41#	define ASSERT_MULTI_WRITE_LOCKED(x) ;
 42#endif
 43
 44
 45class MultiLocker {
 46public:
 47								MultiLocker(const char* baseName);
 48	virtual						~MultiLocker();
 49
 50			status_t			InitCheck();
 51
 52			// locking for reading or writing
 53			bool				ReadLock();
 54			bool				WriteLock();
 55
 56			// unlocking after reading or writing
 57			bool				ReadUnlock();
 58			bool				WriteUnlock();
 59
 60			// does the current thread hold a write lock?
 61			bool				IsWriteLocked() const;
 62
 63#if MULTI_LOCKER_DEBUG
 64			// in DEBUG mode returns whether the lock is held
 65			// in non-debug mode returns true
 66			bool				IsReadLocked() const;
 67#endif
 68
 69private:
 70								MultiLocker();
 71								MultiLocker(const MultiLocker& other);
 72			MultiLocker&		operator=(const MultiLocker& other);
 73									// not implemented
 74
 75#if !MULTI_LOCKER_DEBUG
 76			rw_lock				fLock;
 77#else
 78			// functions for managing the DEBUG reader array
 79			void				_RegisterThread();
 80			void				_UnregisterThread();
 81
 82			sem_id				fLock;
 83			int32*				fDebugArray;
 84			int32				fMaxThreads;
 85			int32				fWriterNest;
 86			thread_id			fWriterThread;
 87#endif	// MULTI_LOCKER_DEBUG
 88
 89			status_t			fInit;
 90
 91#if MULTI_LOCKER_TIMING
 92			uint32 				rl_count;
 93			bigtime_t 			rl_time;
 94			uint32 				ru_count;
 95			bigtime_t	 		ru_time;
 96			uint32				wl_count;
 97			bigtime_t			wl_time;
 98			uint32				wu_count;
 99			bigtime_t			wu_time;
100			uint32				islock_count;
101			bigtime_t			islock_time;
102#endif
103};
104
105
106class AutoWriteLocker {
107public:
108	AutoWriteLocker(MultiLocker* lock)
109		:
110		fLock(*lock)
111	{
112		fLocked = fLock.WriteLock();
113	}
114
115	AutoWriteLocker(MultiLocker& lock)
116		:
117		fLock(lock)
118	{
119		fLocked = fLock.WriteLock();
120	}
121
122	~AutoWriteLocker()
123	{
124		if (fLocked)
125			fLock.WriteUnlock();
126	}
127
128	bool IsLocked() const
129	{
130		return fLock.IsWriteLocked();
131	}
132
133	void Unlock()
134	{
135		if (fLocked) {
136			fLock.WriteUnlock();
137			fLocked = false;
138		}
139	}
140
141private:
142 	MultiLocker&	fLock;
143	bool			fLocked;
144};
145
146
147class AutoReadLocker {
148public:
149	AutoReadLocker(MultiLocker* lock)
150		:
151		fLock(*lock)
152	{
153		fLocked = fLock.ReadLock();
154	}
155
156	AutoReadLocker(MultiLocker& lock)
157		:
158		fLock(lock)
159	{
160		fLocked = fLock.ReadLock();
161	}
162
163	~AutoReadLocker()
164	{
165		Unlock();
166	}
167
168	void Unlock()
169	{
170		if (fLocked) {
171			fLock.ReadUnlock();
172			fLocked = false;
173		}
174	}
175
176private:
177	MultiLocker&	fLock;
178	bool			fLocked;
179};
180
181#endif	// MULTI_LOCKER_H