xref: /haiku/src/servers/app/MultiLocker.h (revision 1acbe440b8dd798953bec31d18ee589aa3f71b73)
1 /*
2  * Copyright 2005-2007, 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 
9 /*! multiple-reader single-writer locking class */
10 
11 // IMPORTANT:
12 //             * nested read locks are not supported
13 //             * a reader becomming the write is not supported
14 //             * nested write locks are supported
15 //             * a writer can do read locks, even nested ones
16 //             * in case of problems, #define DEBUG 1 in the .cpp
17 
18 #ifndef MULTI_LOCKER_H
19 #define MULTI_LOCKER_H
20 
21 
22 #include <OS.h>
23 
24 
25 #define MULTI_LOCKER_TIMING	0
26 #if DEBUG
27 #	define MULTI_LOCKER_DEBUG	DEBUG
28 #else
29 #	define MULTI_LOCKER_DEBUG	0
30 #endif
31 
32 class MultiLocker {
33 	public:
34 		MultiLocker(const char* baseName);
35 		virtual	~MultiLocker();
36 
37 		status_t		InitCheck();
38 
39 		// locking for reading or writing
40 		bool			ReadLock();
41 		bool			WriteLock();
42 
43 		// unlocking after reading or writing
44 		bool			ReadUnlock();
45 		bool			WriteUnlock();
46 
47 		// does the current thread hold a write lock ?
48 		bool			IsWriteLocked(uint32 *stackBase = NULL,
49 							thread_id *thread = NULL);
50 
51 #if MULTI_LOCKER_DEBUG
52 		// in DEBUG mode returns whether the lock is held
53 		// in non-debug mode returns true
54 		bool			IsReadLocked();
55 #endif
56 
57 	private:
58 #if MULTI_LOCKER_DEBUG
59 		// functions for managing the DEBUG reader array
60 		void			_RegisterThread();
61 		void			_UnregisterThread();
62 
63 		sem_id			fLock;
64 		int32*			fDebugArray;
65 		int32			fMaxThreads;
66 #else
67 		// readers adjust count and block on fReadSem when a writer
68 		// hold the lock
69 		int32			fReadCount;
70 		sem_id			fReadSem;
71 		// writers adjust the count and block on fWriteSem
72 		// when readers hold the lock
73 		int32			fWriteCount;
74 		sem_id 			fWriteSem;
75 		// writers must acquire fWriterLock when acquiring a write lock
76 		int32			fLockCount;
77 		sem_id			fWriterLock;
78 #endif	// MULTI_LOCKER_DEBUG
79 
80 		status_t		fInit;
81 		int32			fWriterNest;
82 		thread_id		fWriterThread;
83 		uint32			fWriterStackBase;
84 
85 #if MULTI_LOCKER_TIMING
86 		uint32 			rl_count;
87 		bigtime_t 		rl_time;
88 		uint32 			ru_count;
89 		bigtime_t 		ru_time;
90 		uint32			wl_count;
91 		bigtime_t		wl_time;
92 		uint32			wu_count;
93 		bigtime_t		wu_time;
94 		uint32			islock_count;
95 		bigtime_t		islock_time;
96 #endif
97 };
98 
99 class AutoWriteLocker {
100 	public:
101 		AutoWriteLocker(MultiLocker* lock)
102 			:
103 			fLock(*lock)
104 		{
105 			fLock.WriteLock();
106 		}
107 
108 		AutoWriteLocker(MultiLocker& lock)
109 			:
110 			fLock(lock)
111 		{
112 			fLock.WriteLock();
113 		}
114 
115 		~AutoWriteLocker()
116 		{
117 			fLock.WriteUnlock();
118 		}
119 
120 	private:
121 	 	MultiLocker&	fLock;
122 };
123 
124 class AutoReadLocker {
125 	public:
126 		AutoReadLocker(MultiLocker* lock)
127 			:
128 			fLock(*lock)
129 		{
130 			fLocked = fLock.ReadLock();
131 		}
132 
133 		AutoReadLocker(MultiLocker& lock)
134 			:
135 			fLock(lock)
136 		{
137 			fLocked = fLock.ReadLock();
138 		}
139 
140 		~AutoReadLocker()
141 		{
142 			Unlock();
143 		}
144 
145 		void
146 		Unlock()
147 		{
148 			if (fLocked) {
149 				fLock.ReadUnlock();
150 				fLocked = false;
151 			}
152 		}
153 
154 	private:
155 	 	MultiLocker&	fLock;
156 	 	bool			fLocked;
157 };
158 
159 #endif	// MULTI_LOCKER_H
160