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