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