xref: /haiku/src/servers/app/MultiLocker.h (revision 0eed9183061a7763972bc2589f9c43489cd078ab)
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 
25 
26 #define MULTI_LOCKER_TIMING	0
27 #if DEBUG
28 #	define MULTI_LOCKER_DEBUG	DEBUG
29 #endif
30 
31 #if MULTI_LOCKER_DEBUG
32 #	define ASSERT_MULTI_LOCKED(x) ((x).IsWriteLocked() || (x).IsReadLocked())
33 #	define ASSERT_MULTI_READ_LOCKED(x) ((x).IsReadLocked())
34 #	define ASSERT_MULTI_WRITE_LOCKED(x) ((x).IsWriteLocked())
35 #else
36 #	define MULTI_LOCKER_DEBUG	0
37 #	define ASSERT_MULTI_LOCKED(x) ;
38 #	define ASSERT_MULTI_READ_LOCKED(x) ;
39 #	define ASSERT_MULTI_WRITE_LOCKED(x) ;
40 #endif
41 
42 
43 class MultiLocker {
44 public:
45 								MultiLocker(const char* baseName);
46 	virtual						~MultiLocker();
47 
48 			status_t			InitCheck();
49 
50 			// locking for reading or writing
51 			bool				ReadLock();
52 			bool				WriteLock();
53 
54 			// unlocking after reading or writing
55 			bool				ReadUnlock();
56 			bool				WriteUnlock();
57 
58 			// does the current thread hold a write lock ?
59 			bool				IsWriteLocked(uint32 *stackBase = NULL,
60 									thread_id *thread = NULL);
61 
62 #if MULTI_LOCKER_DEBUG
63 			// in DEBUG mode returns whether the lock is held
64 			// in non-debug mode returns true
65 			bool				IsReadLocked();
66 #endif
67 
68 private:
69 #if MULTI_LOCKER_DEBUG
70 			// functions for managing the DEBUG reader array
71 			void				_RegisterThread();
72 			void				_UnregisterThread();
73 
74 			sem_id				fLock;
75 			int32*				fDebugArray;
76 			int32				fMaxThreads;
77 #else
78 			// readers adjust count and block on fReadSem when a writer
79 			// hold the lock
80 			int32				fReadCount;
81 			sem_id				fReadSem;
82 			// writers adjust the count and block on fWriteSem
83 			// when readers hold the lock
84 			int32				fWriteCount;
85 			sem_id 				fWriteSem;
86 			// writers must acquire fWriterLock when acquiring a write lock
87 			int32				fLockCount;
88 			sem_id				fWriterLock;
89 #endif	// MULTI_LOCKER_DEBUG
90 
91 			status_t			fInit;
92 			int32				fWriterNest;
93 			thread_id			fWriterThread;
94 			uint32				fWriterStackBase;
95 
96 #if MULTI_LOCKER_TIMING
97 			uint32 				rl_count;
98 			bigtime_t 			rl_time;
99 			uint32 				ru_count;
100 			bigtime_t	 		ru_time;
101 			uint32				wl_count;
102 			bigtime_t			wl_time;
103 			uint32				wu_count;
104 			bigtime_t			wu_time;
105 			uint32				islock_count;
106 			bigtime_t			islock_time;
107 #endif
108 };
109 
110 
111 class AutoWriteLocker {
112 public:
113 	AutoWriteLocker(MultiLocker* lock)
114 		:
115 		fLock(*lock)
116 	{
117 		fLock.WriteLock();
118 	}
119 
120 	AutoWriteLocker(MultiLocker& lock)
121 		:
122 		fLock(lock)
123 	{
124 		fLock.WriteLock();
125 	}
126 
127 	bool IsLocked() const
128 	{
129 		return fLock.IsWriteLocked();
130 	}
131 
132 	~AutoWriteLocker()
133 	{
134 		fLock.WriteUnlock();
135 	}
136 
137 private:
138  	MultiLocker&	fLock;
139 };
140 
141 
142 class AutoReadLocker {
143 public:
144 	AutoReadLocker(MultiLocker* lock)
145 		:
146 		fLock(*lock)
147 	{
148 		fLocked = fLock.ReadLock();
149 	}
150 
151 	AutoReadLocker(MultiLocker& lock)
152 		:
153 		fLock(lock)
154 	{
155 		fLocked = fLock.ReadLock();
156 	}
157 
158 	~AutoReadLocker()
159 	{
160 		Unlock();
161 	}
162 
163 	void
164 	Unlock()
165 	{
166 		if (fLocked) {
167 			fLock.ReadUnlock();
168 			fLocked = false;
169 		}
170 	}
171 
172 private:
173 	MultiLocker&	fLock;
174 	bool			fLocked;
175 };
176 
177 #endif	// MULTI_LOCKER_H
178