xref: /haiku/src/servers/app/MultiLocker.h (revision b671e9bbdbd10268a042b4f4cc4317ccd03d105e)
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 								MultiLocker();
70 								MultiLocker(const MultiLocker& other);
71 			MultiLocker&		operator=(const MultiLocker& other);
72 									// not implemented
73 
74 #if MULTI_LOCKER_DEBUG
75 			// functions for managing the DEBUG reader array
76 			void				_RegisterThread();
77 			void				_UnregisterThread();
78 
79 			sem_id				fLock;
80 			int32*				fDebugArray;
81 			int32				fMaxThreads;
82 #else
83 			// readers adjust count and block on fReadSem when a writer
84 			// hold the lock
85 			int32				fReadCount;
86 			sem_id				fReadSem;
87 			// writers adjust the count and block on fWriteSem
88 			// when readers hold the lock
89 			int32				fWriteCount;
90 			sem_id 				fWriteSem;
91 			// writers must acquire fWriterLock when acquiring a write lock
92 			int32				fLockCount;
93 			sem_id				fWriterLock;
94 #endif	// MULTI_LOCKER_DEBUG
95 
96 			status_t			fInit;
97 			int32				fWriterNest;
98 			thread_id			fWriterThread;
99 			uint32				fWriterStackBase;
100 
101 #if MULTI_LOCKER_TIMING
102 			uint32 				rl_count;
103 			bigtime_t 			rl_time;
104 			uint32 				ru_count;
105 			bigtime_t	 		ru_time;
106 			uint32				wl_count;
107 			bigtime_t			wl_time;
108 			uint32				wu_count;
109 			bigtime_t			wu_time;
110 			uint32				islock_count;
111 			bigtime_t			islock_time;
112 #endif
113 };
114 
115 
116 class AutoWriteLocker {
117 public:
118 	AutoWriteLocker(MultiLocker* lock)
119 		:
120 		fLock(*lock)
121 	{
122 		fLocked = fLock.WriteLock();
123 	}
124 
125 	AutoWriteLocker(MultiLocker& lock)
126 		:
127 		fLock(lock)
128 	{
129 		fLocked = fLock.WriteLock();
130 	}
131 
132 	~AutoWriteLocker()
133 	{
134 		if (fLocked)
135 			fLock.WriteUnlock();
136 	}
137 
138 	bool IsLocked() const
139 	{
140 		return fLock.IsWriteLocked();
141 	}
142 
143 	void Unlock()
144 	{
145 		if (fLocked) {
146 			fLock.WriteUnlock();
147 			fLocked = false;
148 		}
149 	}
150 
151 private:
152  	MultiLocker&	fLock;
153 	bool			fLocked;
154 };
155 
156 
157 class AutoReadLocker {
158 public:
159 	AutoReadLocker(MultiLocker* lock)
160 		:
161 		fLock(*lock)
162 	{
163 		fLocked = fLock.ReadLock();
164 	}
165 
166 	AutoReadLocker(MultiLocker& lock)
167 		:
168 		fLock(lock)
169 	{
170 		fLocked = fLock.ReadLock();
171 	}
172 
173 	~AutoReadLocker()
174 	{
175 		Unlock();
176 	}
177 
178 	void Unlock()
179 	{
180 		if (fLocked) {
181 			fLock.ReadUnlock();
182 			fLocked = false;
183 		}
184 	}
185 
186 private:
187 	MultiLocker&	fLock;
188 	bool			fLocked;
189 };
190 
191 #endif	// MULTI_LOCKER_H
192