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 45 class MultiLocker { 46 public: 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 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 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 106 class AutoWriteLocker { 107 public: 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 141 private: 142 MultiLocker& fLock; 143 bool fLocked; 144 }; 145 146 147 class AutoReadLocker { 148 public: 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 176 private: 177 MultiLocker& fLock; 178 bool fLocked; 179 }; 180 181 #endif // MULTI_LOCKER_H 182