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 #if MULTI_LOCKER_DEBUG 70 // functions for managing the DEBUG reader array 71 void _RegisterThread(); 72 void _UnregisterThread(); 73 74 sem_id fLock; 75 int32* fDebugArray; 76 int32 fMaxThreads; 77 #else 78 // readers adjust count and block on fReadSem when a writer 79 // hold the lock 80 int32 fReadCount; 81 sem_id fReadSem; 82 // writers adjust the count and block on fWriteSem 83 // when readers hold the lock 84 int32 fWriteCount; 85 sem_id fWriteSem; 86 // writers must acquire fWriterLock when acquiring a write lock 87 int32 fLockCount; 88 sem_id fWriterLock; 89 #endif // MULTI_LOCKER_DEBUG 90 91 status_t fInit; 92 int32 fWriterNest; 93 thread_id fWriterThread; 94 uint32 fWriterStackBase; 95 96 #if MULTI_LOCKER_TIMING 97 uint32 rl_count; 98 bigtime_t rl_time; 99 uint32 ru_count; 100 bigtime_t ru_time; 101 uint32 wl_count; 102 bigtime_t wl_time; 103 uint32 wu_count; 104 bigtime_t wu_time; 105 uint32 islock_count; 106 bigtime_t islock_time; 107 #endif 108 }; 109 110 111 class AutoWriteLocker { 112 public: 113 AutoWriteLocker(MultiLocker* lock) 114 : 115 fLock(*lock) 116 { 117 fLock.WriteLock(); 118 } 119 120 AutoWriteLocker(MultiLocker& lock) 121 : 122 fLock(lock) 123 { 124 fLock.WriteLock(); 125 } 126 127 bool IsLocked() const 128 { 129 return fLock.IsWriteLocked(); 130 } 131 132 ~AutoWriteLocker() 133 { 134 fLock.WriteUnlock(); 135 } 136 137 private: 138 MultiLocker& fLock; 139 }; 140 141 142 class AutoReadLocker { 143 public: 144 AutoReadLocker(MultiLocker* lock) 145 : 146 fLock(*lock) 147 { 148 fLocked = fLock.ReadLock(); 149 } 150 151 AutoReadLocker(MultiLocker& lock) 152 : 153 fLock(lock) 154 { 155 fLocked = fLock.ReadLock(); 156 } 157 158 ~AutoReadLocker() 159 { 160 Unlock(); 161 } 162 163 void 164 Unlock() 165 { 166 if (fLocked) { 167 fLock.ReadUnlock(); 168 fLocked = false; 169 } 170 } 171 172 private: 173 MultiLocker& fLock; 174 bool fLocked; 175 }; 176 177 #endif // MULTI_LOCKER_H 178