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 ~AutoWriteLocker() 116 { 117 fLock.WriteUnlock(); 118 } 119 120 private: 121 MultiLocker& fLock; 122 }; 123 124 class AutoReadLocker { 125 public: 126 AutoReadLocker(MultiLocker* lock) 127 : 128 fLock(*lock) 129 { 130 fLocked = fLock.ReadLock(); 131 } 132 133 AutoReadLocker(MultiLocker& lock) 134 : 135 fLock(lock) 136 { 137 fLocked = fLock.ReadLock(); 138 } 139 140 ~AutoReadLocker() 141 { 142 Unlock(); 143 } 144 145 void 146 Unlock() 147 { 148 if (fLocked) { 149 fLock.ReadUnlock(); 150 fLocked = false; 151 } 152 } 153 154 private: 155 MultiLocker& fLock; 156 bool fLocked; 157 }; 158 159 #endif // MULTI_LOCKER_H 160