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