1 /* 2 * Copyright 2005-2007, 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 9 /*! multiple-reader single-writer locking class */ 10 11 // IMPORTANT: 12 // * nested read locks are not supported 13 // * a reader becomming the write is not supported 14 // * nested write locks are supported 15 // * a writer can do read locks, even nested ones 16 // * in case of problems, #define DEBUG 1 in the .cpp 17 18 #ifndef MULTI_LOCKER_H 19 #define MULTI_LOCKER_H 20 21 22 #include <OS.h> 23 24 25 #define MULTI_LOCKER_TIMING 0 26 #if DEBUG 27 # define MULTI_LOCKER_DEBUG DEBUG 28 #else 29 # define MULTI_LOCKER_DEBUG 0 30 #endif 31 32 class MultiLocker { 33 public: 34 MultiLocker(const char* baseName); 35 virtual ~MultiLocker(); 36 37 status_t InitCheck(); 38 39 // locking for reading or writing 40 bool ReadLock(); 41 bool WriteLock(); 42 43 // unlocking after reading or writing 44 bool ReadUnlock(); 45 bool WriteUnlock(); 46 47 // does the current thread hold a write lock ? 48 bool IsWriteLocked(uint32 *stackBase = NULL, 49 thread_id *thread = NULL); 50 51 #if MULTI_LOCKER_DEBUG 52 // in DEBUG mode returns whether the lock is held 53 // in non-debug mode returns true 54 bool IsReadLocked(); 55 #endif 56 57 private: 58 #if MULTI_LOCKER_DEBUG 59 // functions for managing the DEBUG reader array 60 void _RegisterThread(); 61 void _UnregisterThread(); 62 63 sem_id fLock; 64 int32* fDebugArray; 65 int32 fMaxThreads; 66 #else 67 // readers adjust count and block on fReadSem when a writer 68 // hold the lock 69 int32 fReadCount; 70 sem_id fReadSem; 71 // writers adjust the count and block on fWriteSem 72 // when readers hold the lock 73 int32 fWriteCount; 74 sem_id fWriteSem; 75 // writers must acquire fWriterLock when acquiring a write lock 76 int32 fLockCount; 77 sem_id fWriterLock; 78 #endif // MULTI_LOCKER_DEBUG 79 80 status_t fInit; 81 int32 fWriterNest; 82 thread_id fWriterThread; 83 uint32 fWriterStackBase; 84 85 #if MULTI_LOCKER_TIMING 86 uint32 rl_count; 87 bigtime_t rl_time; 88 uint32 ru_count; 89 bigtime_t ru_time; 90 uint32 wl_count; 91 bigtime_t wl_time; 92 uint32 wu_count; 93 bigtime_t wu_time; 94 uint32 islock_count; 95 bigtime_t islock_time; 96 #endif 97 }; 98 99 class AutoWriteLocker { 100 public: 101 AutoWriteLocker(MultiLocker* lock) 102 : 103 fLock(*lock) 104 { 105 fLock.WriteLock(); 106 } 107 108 AutoWriteLocker(MultiLocker& lock) 109 : 110 fLock(lock) 111 { 112 fLock.WriteLock(); 113 } 114 115 bool IsLocked() const 116 { 117 return fLock.IsWriteLocked(); 118 } 119 120 ~AutoWriteLocker() 121 { 122 fLock.WriteUnlock(); 123 } 124 125 private: 126 MultiLocker& fLock; 127 }; 128 129 class AutoReadLocker { 130 public: 131 AutoReadLocker(MultiLocker* lock) 132 : 133 fLock(*lock) 134 { 135 fLocked = fLock.ReadLock(); 136 } 137 138 AutoReadLocker(MultiLocker& lock) 139 : 140 fLock(lock) 141 { 142 fLocked = fLock.ReadLock(); 143 } 144 145 ~AutoReadLocker() 146 { 147 Unlock(); 148 } 149 150 void 151 Unlock() 152 { 153 if (fLocked) { 154 fLock.ReadUnlock(); 155 fLocked = false; 156 } 157 } 158 159 private: 160 MultiLocker& fLock; 161 bool fLocked; 162 }; 163 164 #endif // MULTI_LOCKER_H 165