1 /* 2 * Copyright (C) 2002 - David W. Durham 3 * 4 * This file is part of ReZound, an audio editing application. 5 * 6 * ReZound is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published 8 * by the Free Software Foundation; either version 2 of the License, 9 * or (at your option) any later version. 10 * 11 * ReZound is distributed in the hope that it will be useful, but 12 * WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 19 */ 20 #ifndef __CRWMutex_H__ 21 #define __CRWMutex_H__ 22 23 #include "../../config/common.h" 24 25 /* 26 * This is a multi-platform rwlock wrapper. 27 * 28 * The public interface looks like: 29 30 class CRWMutex 31 { 32 public: 33 CRWMutex(); 34 virtual ~CRWMutex() throw(); 35 36 // read-locks can be obtained recursively with other read-locks, but not with other write-locks 37 void readLock(); 38 bool tryReadLock(); 39 size_t getReadLockCount() const; 40 41 // write-locks can be obtained recursively with other write-locks, but not with other read-locks 42 void writeLock(); 43 bool tryWriteLock(); 44 bool isLockedForWrite() const; 45 46 void unlock(); 47 }; 48 49 * 50 * 51 * A utility class exists for dealing with CRWMutexes 52 * The public interface looks like: 53 54 class CRWMutexLocker 55 { 56 public: 57 enum LockTypes 58 { 59 ltReader, 60 ltWriter 61 }; 62 63 // construct a locker object with no mutex assigned 64 CRWMutexLocker(); 65 66 // construct a locker object with the given mutex.. the mutex is locked/try-locked on construction 67 CRWMutexLocker(CRWMutex &_m,LockTypes lockType,bool block=true); 68 69 // the destructor unlocks the mutex iff it was locked 70 virtual ~CRWMutexLocker() throw(); 71 72 // returned whether the mutex lock was obtained by this object (sometimes false if a try-lock occurred) 73 bool didLock() const; 74 75 // unlocks the currently assigned mutex if it was locked, assigns a new mutex to this locked and locks/try-locks the new mutex 76 // the locked status is returned 77 bool reassign(CRWMutex &_m,LockTypes lockType,bool block=true); 78 79 // unlocks the currently assigned mutex if it was locked and leaves the locker object with no assigned mutex 80 void unassign(); 81 }; 82 83 */ 84 85 // a skeleton stub for extenting functionality 86 class ARWMutex 87 { 88 public: 89 90 ARWMutex() {} 91 virtual ~ARWMutex() throw() {} 92 93 virtual void readLock() {} 94 virtual bool tryReadLock() { return false; } 95 96 virtual void writeLock() {} 97 virtual bool tryWriteLock() { return false; } 98 99 virtual void unlock() {} 100 }; 101 102 #ifdef _WIN32 103 // *** WIN32 implementation *** 104 // based on code in the PTypes library: http://www.melikyan.com/ptypes/ 105 106 #include "CMutex.h" 107 108 class CRWMutex : public ARWMutex 109 { 110 public: 111 112 CRWMutex(); 113 virtual ~CRWMutex() throw(); 114 115 void readLock(); 116 bool tryReadLock(); 117 size_t getReadLockCount() const { return readcnt+1; } 118 119 void writeLock(); 120 bool tryWriteLock(); 121 bool isLockedForWrite() const { return writecnt>0; } 122 123 void unlock(); 124 125 private: 126 void *reading; // ??? would make this HANDLE, but really don't think I need to include a 30k line header file for it 127 void *finished; // ??? would make this HANDLE, but really don't think I need to include a 30k line header file for it 128 int readcnt; 129 int writecnt; 130 131 CMutex wrMutex; 132 }; 133 134 135 136 #else 137 // *** posix implementation *** 138 139 #include <pthread.h> 140 #include "CAtomicCounter.h" 141 142 class CRWMutex : public ARWMutex 143 { 144 public: 145 146 CRWMutex(); 147 virtual ~CRWMutex() throw(); 148 149 void readLock(); 150 bool tryReadLock(); 151 size_t getReadLockCount() const { return readLockCount.value(); } 152 153 void writeLock(); 154 bool tryWriteLock(); 155 bool isLockedForWrite() const { return writeLockCount.value()>0; } 156 157 void unlock(); 158 159 private: 160 pthread_rwlock_t rwlock; 161 162 // even though only one write lock can be aquired, it can be locked more than once 163 // if the thread currently holding the write-lock locks again (which is allowed) 164 mutable CAtomicCounter writeLockCount; 165 void *writeLockOwner; 166 167 mutable CAtomicCounter readLockCount; 168 169 }; 170 171 #endif 172 173 174 /* 175 * This class simply locks the given mutex on construct and unlocks on destruction 176 * it is useful to use where a lock should be obtained, then released on return or 177 * exception... when an object of this class goes out of scope, the lock will be 178 * released 179 * 180 * The construct can optionally take a second parameter that says not to wait when 181 * locking, but to do a trylock. If this method is used, then it is necessary to 182 * call didLock() to see if a lock was obtained. 183 */ 184 // TODO: dispatcher performance testing was ~2% faster if these methods were made inline 185 class CRWMutexLocker 186 { 187 public: 188 enum LockTypes 189 { 190 ltReader, 191 ltWriter 192 }; 193 194 // construct a locker object with no mutex assigned 195 CRWMutexLocker(); 196 197 // construct a locker object with the given mutex.. the mutex is locked/try-locked on construction 198 CRWMutexLocker(CRWMutex &_m,LockTypes lockType,bool block=true); 199 200 // the destructor unlocks the mutex iff it was locked 201 virtual ~CRWMutexLocker() throw(); 202 203 // returned whether the mutex lock was obtained by this object (sometimes false if a try-lock occurred) 204 bool didLock() const { return locked; } 205 206 // unlocks the currently assigned mutex if it was locked, assigns a new mutex to this locked and locks/try-locks the new mutex 207 // the locked status is returned 208 bool reassign(CRWMutex &_m,LockTypes lockType,bool block=true); 209 210 // unlocks the currently assigned mutex if it was locked and leaves the locker object with no assigned mutex 211 void unassign(); 212 213 private: 214 CRWMutex *m; 215 bool locked; 216 }; 217 218 219 220 221 #endif 222 223