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 # define MULTI_LOCKER_DEBUG DEBUG 29 #endif 30 31 #if MULTI_LOCKER_DEBUG 32 # define ASSERT_MULTI_LOCKED(x) ((x).IsWriteLocked() || (x).IsReadLocked()) 33 # define ASSERT_MULTI_READ_LOCKED(x) ((x).IsReadLocked()) 34 # define ASSERT_MULTI_WRITE_LOCKED(x) ((x).IsWriteLocked()) 35 #else 36 # define MULTI_LOCKER_DEBUG 0 37 # define ASSERT_MULTI_LOCKED(x) ; 38 # define ASSERT_MULTI_READ_LOCKED(x) ; 39 # define ASSERT_MULTI_WRITE_LOCKED(x) ; 40 #endif 41 42 43 class MultiLocker { 44 public: 45 MultiLocker(const char* baseName); 46 virtual ~MultiLocker(); 47 48 status_t InitCheck(); 49 50 // locking for reading or writing 51 bool ReadLock(); 52 bool WriteLock(); 53 54 // unlocking after reading or writing 55 bool ReadUnlock(); 56 bool WriteUnlock(); 57 58 // does the current thread hold a write lock ? 59 bool IsWriteLocked(uint32 *stackBase = NULL, 60 thread_id *thread = NULL); 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(); 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 uint32 fWriterStackBase; 100 101 #if MULTI_LOCKER_TIMING 102 uint32 rl_count; 103 bigtime_t rl_time; 104 uint32 ru_count; 105 bigtime_t ru_time; 106 uint32 wl_count; 107 bigtime_t wl_time; 108 uint32 wu_count; 109 bigtime_t wu_time; 110 uint32 islock_count; 111 bigtime_t islock_time; 112 #endif 113 }; 114 115 116 class AutoWriteLocker { 117 public: 118 AutoWriteLocker(MultiLocker* lock) 119 : 120 fLock(*lock) 121 { 122 fLocked = fLock.WriteLock(); 123 } 124 125 AutoWriteLocker(MultiLocker& lock) 126 : 127 fLock(lock) 128 { 129 fLocked = fLock.WriteLock(); 130 } 131 132 ~AutoWriteLocker() 133 { 134 if (fLocked) 135 fLock.WriteUnlock(); 136 } 137 138 bool IsLocked() const 139 { 140 return fLock.IsWriteLocked(); 141 } 142 143 void Unlock() 144 { 145 if (fLocked) { 146 fLock.WriteUnlock(); 147 fLocked = false; 148 } 149 } 150 151 private: 152 MultiLocker& fLock; 153 bool fLocked; 154 }; 155 156 157 class AutoReadLocker { 158 public: 159 AutoReadLocker(MultiLocker* lock) 160 : 161 fLock(*lock) 162 { 163 fLocked = fLock.ReadLock(); 164 } 165 166 AutoReadLocker(MultiLocker& lock) 167 : 168 fLock(lock) 169 { 170 fLocked = fLock.ReadLock(); 171 } 172 173 ~AutoReadLocker() 174 { 175 Unlock(); 176 } 177 178 void Unlock() 179 { 180 if (fLocked) { 181 fLock.ReadUnlock(); 182 fLocked = false; 183 } 184 } 185 186 private: 187 MultiLocker& fLock; 188 bool fLocked; 189 }; 190 191 #endif // MULTI_LOCKER_H 192