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