xref: /haiku/src/servers/app/MultiLocker.h (revision f9c77b11edcf7eee58dd866cb89364def0778110)
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() const;
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() const;
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 
100 #if MULTI_LOCKER_TIMING
101 			uint32 				rl_count;
102 			bigtime_t 			rl_time;
103 			uint32 				ru_count;
104 			bigtime_t	 		ru_time;
105 			uint32				wl_count;
106 			bigtime_t			wl_time;
107 			uint32				wu_count;
108 			bigtime_t			wu_time;
109 			uint32				islock_count;
110 			bigtime_t			islock_time;
111 #endif
112 };
113 
114 
115 class AutoWriteLocker {
116 public:
117 	AutoWriteLocker(MultiLocker* lock)
118 		:
119 		fLock(*lock)
120 	{
121 		fLocked = fLock.WriteLock();
122 	}
123 
124 	AutoWriteLocker(MultiLocker& lock)
125 		:
126 		fLock(lock)
127 	{
128 		fLocked = fLock.WriteLock();
129 	}
130 
131 	~AutoWriteLocker()
132 	{
133 		if (fLocked)
134 			fLock.WriteUnlock();
135 	}
136 
137 	bool IsLocked() const
138 	{
139 		return fLock.IsWriteLocked();
140 	}
141 
142 	void Unlock()
143 	{
144 		if (fLocked) {
145 			fLock.WriteUnlock();
146 			fLocked = false;
147 		}
148 	}
149 
150 private:
151  	MultiLocker&	fLock;
152 	bool			fLocked;
153 };
154 
155 
156 class AutoReadLocker {
157 public:
158 	AutoReadLocker(MultiLocker* lock)
159 		:
160 		fLock(*lock)
161 	{
162 		fLocked = fLock.ReadLock();
163 	}
164 
165 	AutoReadLocker(MultiLocker& lock)
166 		:
167 		fLock(lock)
168 	{
169 		fLocked = fLock.ReadLock();
170 	}
171 
172 	~AutoReadLocker()
173 	{
174 		Unlock();
175 	}
176 
177 	void Unlock()
178 	{
179 		if (fLocked) {
180 			fLock.ReadUnlock();
181 			fLocked = false;
182 		}
183 	}
184 
185 private:
186 	MultiLocker&	fLock;
187 	bool			fLocked;
188 };
189 
190 #endif	// MULTI_LOCKER_H
191