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