![]() |
pl-nk v0.4.5
Plonk|Plink|Plank are a set of cross-platform C/C++ frameworks for audio software development
|
00001 /* 00002 ------------------------------------------------------------------------------- 00003 This file is part of the Plink, Plonk, Plank libraries 00004 by Martin Robinson 00005 00006 http://code.google.com/p/pl-nk/ 00007 00008 Copyright University of the West of England, Bristol 2011-14 00009 All rights reserved. 00010 00011 Redistribution and use in source and binary forms, with or without 00012 modification, are permitted provided that the following conditions are met: 00013 00014 * Redistributions of source code must retain the above copyright 00015 notice, this list of conditions and the following disclaimer. 00016 * Redistributions in binary form must reproduce the above copyright 00017 notice, this list of conditions and the following disclaimer in the 00018 documentation and/or other materials provided with the distribution. 00019 * Neither the name of University of the West of England, Bristol nor 00020 the names of its contributors may be used to endorse or promote products 00021 derived from this software without specific prior written permission. 00022 00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 00024 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00025 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00026 DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF THE WEST OF ENGLAND, BRISTOL BE 00027 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00028 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 00029 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00030 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00031 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 00032 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00033 00034 This software makes use of third party libraries. For more information see: 00035 doc/license.txt included in the distribution. 00036 ------------------------------------------------------------------------------- 00037 */ 00038 00039 #ifndef PLONK_LOCK_H 00040 #define PLONK_LOCK_H 00041 00042 #include "plonk_CoreForwardDeclarations.h" 00043 #include "plonk_SmartPointer.h" 00044 #include "plonk_WeakPointer.h" 00045 #include "plonk_SmartPointerContainer.h" 00046 00047 class LockInternalBase : public SmartPointer 00048 { 00049 public: 00050 LockInternalBase() throw() : SmartPointer (false) { } // no weak ref needed 00051 ~LockInternalBase() { } 00052 00053 virtual void lock() throw() = 0; 00054 virtual void unlock() throw() = 0; 00055 virtual bool tryLock() throw() = 0; 00056 virtual void wait (const double time) throw() = 0; 00057 virtual void signal() throw() = 0; 00058 00059 }; 00060 00061 class NoLockInternal : public LockInternalBase 00062 { 00063 public: 00064 NoLockInternal() throw() { } 00065 ~NoLockInternal() { } 00066 00067 void lock() throw() { } 00068 void unlock() throw() { } 00069 bool tryLock() throw() { return true; } 00070 void wait (const double time) throw() { (void)time; } 00071 void signal() throw() { } 00072 00073 private: 00074 }; 00075 00076 class LockInternal : public LockInternalBase 00077 { 00078 public: 00079 LockInternal() throw(); 00080 ~LockInternal(); 00081 00082 void lock() throw(); 00083 void unlock() throw(); 00084 bool tryLock() throw(); 00085 void wait (const double time) throw(); 00086 void signal() throw(); 00087 00088 private: 00089 inline PlankLockRef getPeerRef() { return &l; } 00090 PlankLock l; 00091 }; 00092 00093 class SpinLockInternal : public LockInternalBase 00094 { 00095 public: 00096 SpinLockInternal() throw(); 00097 ~SpinLockInternal(); 00098 00099 void lock() throw(); 00100 void unlock() throw(); 00101 bool tryLock() throw(); 00102 void wait (const double time) throw(); 00103 void signal() throw(); 00104 00105 private: 00106 inline PlankSpinLockRef getPeerRef() { return &l; } 00107 PlankSpinLock l; 00108 }; 00109 00110 class ThreadSpinLockInternal : public LockInternalBase 00111 { 00112 public: 00113 ThreadSpinLockInternal() throw(); 00114 ~ThreadSpinLockInternal(); 00115 00116 void lock() throw(); 00117 void unlock() throw(); 00118 bool tryLock() throw(); 00119 void wait (const double time) throw(); 00120 void signal() throw(); 00121 00122 private: 00123 inline PlankThreadSpinLockRef getPeerRef() { return &l; } 00124 PlankThreadSpinLock l; 00125 }; 00126 00127 00128 //------------------------------------------------------------------------------ 00129 00131 class Lock : public SmartPointerContainer<LockInternalBase> 00132 { 00133 public: 00134 typedef SmartPointerContainer<LockInternalBase> Base; 00135 00136 enum Type 00137 { 00138 NoLock, 00139 MutexLock, 00140 SpinLock, 00141 ThreadSpinLock, 00142 NumTypes 00143 }; 00144 00145 Lock (const Lock::Type lockType = MutexLock) throw(); 00146 00147 explicit Lock (LockInternalBase* internalToUse) throw(); 00148 00150 Lock (Lock const& copy) throw(); 00151 Lock& operator= (Lock const& other) throw(); 00152 00153 inline void lock() throw() { getInternal()->lock(); } 00154 inline void unlock() throw() { getInternal()->unlock(); } 00155 inline bool tryLock() throw() { return getInternal()->tryLock(); } 00156 inline void wait() throw() { getInternal()->wait (0.0); } 00157 inline void wait (const double time) throw() { getInternal()->wait (time); } 00158 inline void signal() throw() { getInternal()->signal(); } 00159 00160 PLONK_OBJECTARROWOPERATOR(Lock); 00161 00162 private: 00163 static LockInternalBase* lockInternalFromType (const int lockType) throw(); 00164 }; 00165 00166 //------------------------------------------------------------------------------ 00167 00169 class AutoLock 00170 { 00171 public: 00172 AutoLock (Lock const& lock = Lock::MutexLock) throw(); 00173 ~AutoLock(); 00174 00175 private: 00176 Lock theLock; 00177 00178 AutoLock (AutoLock const&); 00179 AutoLock& operator= (AutoLock const&); 00180 }; 00181 00182 //------------------------------------------------------------------------------ 00183 00185 class AutoUnlock 00186 { 00187 public: 00188 AutoUnlock (Lock const& lock = Lock::MutexLock) throw(); 00189 ~AutoUnlock(); 00190 00191 private: 00192 Lock theLock; 00193 00194 AutoUnlock (AutoUnlock const&); 00195 AutoUnlock& operator= (AutoUnlock const&); 00196 }; 00197 00198 //------------------------------------------------------------------------------ 00199 00201 class AutoTryLock 00202 { 00203 public: 00204 AutoTryLock (Lock const& lock = Lock::MutexLock, bool* didLock = 0) throw(); 00205 ~AutoTryLock(); 00206 00207 bool getDidLock() const throw() { return didLock; } 00208 00209 private: 00210 Lock theLock; 00211 bool didLock; 00212 00213 AutoTryLock (AutoTryLock const&); 00214 AutoTryLock& operator= (AutoTryLock const&); 00215 }; 00216 00217 //------------------------------------------------------------------------------ 00218 00219 template<class ValueType> 00220 class LockedValueInternal : public SmartPointer 00221 { 00222 public: 00223 LockedValueInternal (ValueType const& initialValue, Lock const& lockToUse) 00224 : value (initialValue), 00225 lock (lockToUse) 00226 { 00227 } 00228 00229 void setValue (ValueType const& newValue) throw() 00230 { 00231 const AutoLock l (lock); 00232 value = newValue; 00233 } 00234 00235 bool trySetValue (ValueType const& newValue) throw() 00236 { 00237 const AutoTryLock l (lock); 00238 00239 if (l.getDidLock()) 00240 { 00241 value = newValue; 00242 return true; 00243 } 00244 00245 return false; 00246 } 00247 00248 ValueType getValue() const throw() 00249 { 00250 ValueType tmp; 00251 00252 const AutoLock l (lock); 00253 tmp = value; 00254 return tmp; 00255 } 00256 00257 inline Lock& getLock() throw() { return lock; } 00258 00259 private: 00260 ValueType value; 00261 Lock lock; 00262 }; 00263 00269 template<class Type> 00270 class LockedValue : public SmartPointerContainer< LockedValueInternal<Type> > 00271 { 00272 public: 00273 typedef LockedValueInternal<Type> Internal; 00274 typedef SmartPointerContainer<Internal> Base; 00275 typedef Type ValueType; 00276 00277 LockedValue (Type const& value = Type(), 00278 Lock const& lock = Lock::SpinLock) 00279 : Base (new Internal (value, lock)) 00280 { 00281 } 00282 00283 LockedValue (LockedValue const& copy) throw() 00284 : Base (static_cast<Base> (copy)) 00285 { 00286 } 00287 00288 LockedValue& operator= (LockedValue const& other) throw() 00289 { 00290 if (this != &other) 00291 this->setInternal (other.getInternal()); 00292 00293 return *this; 00294 } 00295 00296 inline LockedValue& operator= (Type const& other) throw() 00297 { 00298 this->setValue (other); 00299 return *this; 00300 } 00301 00302 inline void setValue (Type const& newValue) throw() 00303 { 00304 this->getInternal()->setValue (newValue); 00305 } 00306 00307 inline bool trySetValue (Type const& newValue) throw() 00308 { 00309 return this->getInternal()->trySetValue (newValue); 00310 } 00311 00312 inline Type getValue() const throw() 00313 { 00314 return this->getInternal()->getValue(); 00315 } 00316 00317 inline operator Type() const throw() 00318 { 00319 return this->getInternal()->getValue(); 00320 } 00321 00322 PLONK_OBJECTARROWOPERATOR(LockedValue); 00323 00324 template<typename Function> 00325 inline void operator() (VoidReturn::Type ret, Function function) 00326 { 00327 (void)ret; 00328 Type value = this->getValue(); 00329 const AutoLock l (this->getInternal()->getLock()); 00330 (value.*function)(); 00331 } 00332 00333 template<typename Function, class Arg1Type> 00334 inline void operator() (VoidReturn::Type ret, Function function, Arg1Type arg1) 00335 { 00336 (void)ret; 00337 Type value = this->getValue(); 00338 const AutoLock l (this->getInternal()->getLock()); 00339 (value.*function)(arg1); 00340 } 00341 00342 template<typename Function, class Arg1Type, class Arg2Type> 00343 inline void operator() (VoidReturn::Type ret, Function function, Arg1Type arg1, Arg2Type arg2) 00344 { 00345 (void)ret; 00346 Type value = this->getValue(); 00347 const AutoLock l (this->getInternal()->getLock()); 00348 (value.*function)(arg1, arg2); 00349 } 00350 00351 template<class ReturnType, typename Function, class Arg1Type, class Arg2Type, class Arg3Type> 00352 inline void operator() (VoidReturn::Type ret, Function function, Arg1Type arg1, Arg2Type arg2, Arg3Type arg3) 00353 { 00354 (void)ret; 00355 Type value = this->getValue(); 00356 const AutoLock l (this->getInternal()->getLock()); 00357 (value.*function)(arg1, arg2, arg3); 00358 } 00359 00360 template<class ReturnType, typename Function> 00361 inline void operator() (ReturnType* ret, Function function) 00362 { 00363 Type value = this->getValue(); 00364 00365 if (ret) 00366 { 00367 const AutoLock l (this->getInternal()->getLock()); 00368 *ret = (value.*function)(); 00369 } 00370 else 00371 { 00372 (*this)(VoidReturn::Pass, function); 00373 } 00374 } 00375 00376 template<class ReturnType, typename Function, class Arg1Type> 00377 inline void operator() (ReturnType* ret, Function function, Arg1Type arg1) 00378 { 00379 Type value = this->getValue(); 00380 00381 if (ret) 00382 { 00383 const AutoLock l (this->getInternal()->getLock()); 00384 *ret = (value.*function)(arg1); 00385 } 00386 else 00387 { 00388 (*this)(VoidReturn::Pass, function, arg1); 00389 } 00390 } 00391 00392 template<class ReturnType, typename Function, class Arg1Type, class Arg2Type> 00393 inline void operator() (ReturnType* ret, Function function, Arg1Type arg1, Arg2Type arg2) 00394 { 00395 Type value = this->getValue(); 00396 00397 if (ret) 00398 { 00399 const AutoLock l (this->getInternal()->getLock()); 00400 *ret = (value.*function)(arg1, arg2); 00401 } 00402 else 00403 { 00404 (*this)(VoidReturn::Pass, function, arg1, arg2); 00405 } 00406 } 00407 00408 template<class ReturnType, typename Function, class Arg1Type, class Arg2Type, class Arg3Type> 00409 inline void operator() (ReturnType* ret, Function function, Arg1Type arg1, Arg2Type arg2, Arg3Type arg3) 00410 { 00411 Type value = this->getValue(); 00412 00413 if (ret) 00414 { 00415 const AutoLock l (this->getInternal()->getLock()); 00416 *ret = (value.*function)(arg1, arg2, arg3); 00417 } 00418 else 00419 { 00420 (*this)(VoidReturn::Pass, function, arg1, arg2, arg3); 00421 } 00422 } 00423 00424 inline Lock& getLock() throw() { return this->getInternal()->getLock(); } 00425 00426 inline void lock() throw() { this->getLock().lock(); } 00427 inline void unlock() throw() { this->getLock().unlock(); } 00428 inline bool tryLock() throw() { return this->getLock().tryLock(); } 00429 00430 }; 00431 00432 #define PLONK_LOCKEDVALUE_CALL(VALUETYPE, LOCKEDVALUE, FUNCTION, ARGS) \ 00433 do {\ 00434 VALUETYPE value = LOCKEDVALUE.getValue();\ 00435 const AutoLock l (LOCKEDVALUE.getLock());\ 00436 value.FUNCTION ARGS;\ 00437 } while (false);\ 00438 00439 #define PLONK_LOCKEDVALUE_CALLRETURN(VALUETYPE, RETURNEXPR, LOCKEDVALUE, FUNCTION, ARGS) \ 00440 do {\ 00441 VALUETYPE value = LOCKEDVALUE.getValue();\ 00442 const AutoLock l (LOCKEDVALUE.getLock());\ 00443 RETURNEXPR value.FUNCTION ARGS;\ 00444 } while (false);\ 00445 00446 00447 #endif // PLONK_LOCK_H