1*b1cdbd2cSJim Jagielski /************************************************************** 2*b1cdbd2cSJim Jagielski * 3*b1cdbd2cSJim Jagielski * Licensed to the Apache Software Foundation (ASF) under one 4*b1cdbd2cSJim Jagielski * or more contributor license agreements. See the NOTICE file 5*b1cdbd2cSJim Jagielski * distributed with this work for additional information 6*b1cdbd2cSJim Jagielski * regarding copyright ownership. The ASF licenses this file 7*b1cdbd2cSJim Jagielski * to you under the Apache License, Version 2.0 (the 8*b1cdbd2cSJim Jagielski * "License"); you may not use this file except in compliance 9*b1cdbd2cSJim Jagielski * with the License. You may obtain a copy of the License at 10*b1cdbd2cSJim Jagielski * 11*b1cdbd2cSJim Jagielski * http://www.apache.org/licenses/LICENSE-2.0 12*b1cdbd2cSJim Jagielski * 13*b1cdbd2cSJim Jagielski * Unless required by applicable law or agreed to in writing, 14*b1cdbd2cSJim Jagielski * software distributed under the License is distributed on an 15*b1cdbd2cSJim Jagielski * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*b1cdbd2cSJim Jagielski * KIND, either express or implied. See the License for the 17*b1cdbd2cSJim Jagielski * specific language governing permissions and limitations 18*b1cdbd2cSJim Jagielski * under the License. 19*b1cdbd2cSJim Jagielski * 20*b1cdbd2cSJim Jagielski *************************************************************/ 21*b1cdbd2cSJim Jagielski 22*b1cdbd2cSJim Jagielski 23*b1cdbd2cSJim Jagielski 24*b1cdbd2cSJim Jagielski #ifndef __FRAMEWORK_THREADHELP_FAIRRWLOCK_HXX_ 25*b1cdbd2cSJim Jagielski #define __FRAMEWORK_THREADHELP_FAIRRWLOCK_HXX_ 26*b1cdbd2cSJim Jagielski 27*b1cdbd2cSJim Jagielski //_________________________________________________________________________________________________________________ 28*b1cdbd2cSJim Jagielski // my own includes 29*b1cdbd2cSJim Jagielski //_________________________________________________________________________________________________________________ 30*b1cdbd2cSJim Jagielski 31*b1cdbd2cSJim Jagielski #include <threadhelp/inoncopyable.h> 32*b1cdbd2cSJim Jagielski #include <threadhelp/irwlock.h> 33*b1cdbd2cSJim Jagielski #include <macros/debug.hxx> 34*b1cdbd2cSJim Jagielski 35*b1cdbd2cSJim Jagielski //_________________________________________________________________________________________________________________ 36*b1cdbd2cSJim Jagielski // interface includes 37*b1cdbd2cSJim Jagielski //_________________________________________________________________________________________________________________ 38*b1cdbd2cSJim Jagielski #include <com/sun/star/uno/XInterface.hpp> 39*b1cdbd2cSJim Jagielski 40*b1cdbd2cSJim Jagielski //_________________________________________________________________________________________________________________ 41*b1cdbd2cSJim Jagielski // other includes 42*b1cdbd2cSJim Jagielski //_________________________________________________________________________________________________________________ 43*b1cdbd2cSJim Jagielski #include <osl/mutex.hxx> 44*b1cdbd2cSJim Jagielski #include <osl/conditn.hxx> 45*b1cdbd2cSJim Jagielski 46*b1cdbd2cSJim Jagielski //_________________________________________________________________________________________________________________ 47*b1cdbd2cSJim Jagielski // namespace 48*b1cdbd2cSJim Jagielski //_________________________________________________________________________________________________________________ 49*b1cdbd2cSJim Jagielski 50*b1cdbd2cSJim Jagielski namespace framework{ 51*b1cdbd2cSJim Jagielski 52*b1cdbd2cSJim Jagielski //_________________________________________________________________________________________________________________ 53*b1cdbd2cSJim Jagielski // const 54*b1cdbd2cSJim Jagielski //_________________________________________________________________________________________________________________ 55*b1cdbd2cSJim Jagielski 56*b1cdbd2cSJim Jagielski //_________________________________________________________________________________________________________________ 57*b1cdbd2cSJim Jagielski // declarations 58*b1cdbd2cSJim Jagielski //_________________________________________________________________________________________________________________ 59*b1cdbd2cSJim Jagielski 60*b1cdbd2cSJim Jagielski /*-************************************************************************************************************//** 61*b1cdbd2cSJim Jagielski @short implement a read/write lock with fairness between read/write accessors 62*b1cdbd2cSJim Jagielski @descr These implementation never should used as base class! Use it as a member every time. 63*b1cdbd2cSJim Jagielski Use ReadGuard and/or WriteGuard in your methods (which work with these lock) 64*b1cdbd2cSJim Jagielski to make your code threadsafe. 65*b1cdbd2cSJim Jagielski Fair means: All reading or writing threads are synchronized AND serialzed by using one 66*b1cdbd2cSJim Jagielski mutex. For reader this mutex is used to access internal variables of this lock only; 67*b1cdbd2cSJim Jagielski for writer this mutex is used to have an exclusiv access on your class member! 68*b1cdbd2cSJim Jagielski => It's a multi-reader/single-writer lock, which no preferred accessor. 69*b1cdbd2cSJim Jagielski 70*b1cdbd2cSJim Jagielski @implements IRWlock 71*b1cdbd2cSJim Jagielski @base INonCopyable 72*b1cdbd2cSJim Jagielski IRWLock 73*b1cdbd2cSJim Jagielski 74*b1cdbd2cSJim Jagielski @devstatus ready to use 75*b1cdbd2cSJim Jagielski *//*-*************************************************************************************************************/ 76*b1cdbd2cSJim Jagielski class FairRWLock : public IRWLock 77*b1cdbd2cSJim Jagielski , private INonCopyable 78*b1cdbd2cSJim Jagielski { 79*b1cdbd2cSJim Jagielski //------------------------------------------------------------------------------------------------------------- 80*b1cdbd2cSJim Jagielski // public methods 81*b1cdbd2cSJim Jagielski //------------------------------------------------------------------------------------------------------------- 82*b1cdbd2cSJim Jagielski public: 83*b1cdbd2cSJim Jagielski 84*b1cdbd2cSJim Jagielski /*-****************************************************************************************************//** 85*b1cdbd2cSJim Jagielski @short standard ctor 86*b1cdbd2cSJim Jagielski @descr Initialize instance with right start values for correct working. 87*b1cdbd2cSJim Jagielski no reader could exist => m_nReadCount = 0 88*b1cdbd2cSJim Jagielski don't block first comming writer => m_aWriteCondition.set() 89*b1cdbd2cSJim Jagielski 90*b1cdbd2cSJim Jagielski @seealso - 91*b1cdbd2cSJim Jagielski 92*b1cdbd2cSJim Jagielski @param - 93*b1cdbd2cSJim Jagielski @return - 94*b1cdbd2cSJim Jagielski 95*b1cdbd2cSJim Jagielski @onerror - 96*b1cdbd2cSJim Jagielski *//*-*****************************************************************************************************/ FairRWLock()97*b1cdbd2cSJim Jagielski inline FairRWLock() 98*b1cdbd2cSJim Jagielski : m_nReadCount( 0 ) 99*b1cdbd2cSJim Jagielski { 100*b1cdbd2cSJim Jagielski m_aWriteCondition.set(); 101*b1cdbd2cSJim Jagielski } 102*b1cdbd2cSJim Jagielski ~FairRWLock()103*b1cdbd2cSJim Jagielski inline virtual ~FairRWLock() 104*b1cdbd2cSJim Jagielski { 105*b1cdbd2cSJim Jagielski } 106*b1cdbd2cSJim Jagielski 107*b1cdbd2cSJim Jagielski /*-****************************************************************************************************//** 108*b1cdbd2cSJim Jagielski @interface IRWLock 109*b1cdbd2cSJim Jagielski @short set lock for reading 110*b1cdbd2cSJim Jagielski @descr A guard should call this method to acquire read access on your member. 111*b1cdbd2cSJim Jagielski Writing isn't allowed then - but nobody could check it for you! 112*b1cdbd2cSJim Jagielski 113*b1cdbd2cSJim Jagielski @seealso method releaseReadAccess() 114*b1cdbd2cSJim Jagielski 115*b1cdbd2cSJim Jagielski @param - 116*b1cdbd2cSJim Jagielski @return - 117*b1cdbd2cSJim Jagielski 118*b1cdbd2cSJim Jagielski @onerror - 119*b1cdbd2cSJim Jagielski *//*-*****************************************************************************************************/ acquireReadAccess()120*b1cdbd2cSJim Jagielski inline virtual void acquireReadAccess() 121*b1cdbd2cSJim Jagielski { 122*b1cdbd2cSJim Jagielski // Put call in "SERIALIZE"-queue! 123*b1cdbd2cSJim Jagielski // After successful acquiring this mutex we are alone ... 124*b1cdbd2cSJim Jagielski ::osl::MutexGuard aSerializeGuard( m_aSerializer ); 125*b1cdbd2cSJim Jagielski 126*b1cdbd2cSJim Jagielski // ... but we should synchronize us with other reader! 127*b1cdbd2cSJim Jagielski // May be - they will unregister himself by using releaseReadAccess()! 128*b1cdbd2cSJim Jagielski ::osl::MutexGuard aAccessGuard( m_aAccessLock ); 129*b1cdbd2cSJim Jagielski 130*b1cdbd2cSJim Jagielski // Now we must register us as reader by increasing counter. 131*b1cdbd2cSJim Jagielski // If this the first writer we must close door for possible writer. 132*b1cdbd2cSJim Jagielski // Other reader don't look for this barrier - they work parallel to us! 133*b1cdbd2cSJim Jagielski if( m_nReadCount == 0 ) 134*b1cdbd2cSJim Jagielski { 135*b1cdbd2cSJim Jagielski m_aWriteCondition.reset(); 136*b1cdbd2cSJim Jagielski } 137*b1cdbd2cSJim Jagielski ++m_nReadCount; 138*b1cdbd2cSJim Jagielski } 139*b1cdbd2cSJim Jagielski 140*b1cdbd2cSJim Jagielski /*-****************************************************************************************************//** 141*b1cdbd2cSJim Jagielski @interface IRWLock 142*b1cdbd2cSJim Jagielski @short reset lock for reading 143*b1cdbd2cSJim Jagielski @descr A guard should call this method to release read access on your member. 144*b1cdbd2cSJim Jagielski 145*b1cdbd2cSJim Jagielski @seealso method acquireReadAccess() 146*b1cdbd2cSJim Jagielski 147*b1cdbd2cSJim Jagielski @param - 148*b1cdbd2cSJim Jagielski @return - 149*b1cdbd2cSJim Jagielski 150*b1cdbd2cSJim Jagielski @onerror - 151*b1cdbd2cSJim Jagielski *//*-*****************************************************************************************************/ releaseReadAccess()152*b1cdbd2cSJim Jagielski inline virtual void releaseReadAccess() 153*b1cdbd2cSJim Jagielski { 154*b1cdbd2cSJim Jagielski // The access lock is enough at this point 155*b1cdbd2cSJim Jagielski // because it's not allowed to wait for all reader or writer here! 156*b1cdbd2cSJim Jagielski // That will cause a deadlock! 157*b1cdbd2cSJim Jagielski ::osl::MutexGuard aAccessGuard( m_aAccessLock ); 158*b1cdbd2cSJim Jagielski 159*b1cdbd2cSJim Jagielski // Unregister as reader first! 160*b1cdbd2cSJim Jagielski // Open writer barrier then if it was the last reader. 161*b1cdbd2cSJim Jagielski --m_nReadCount; 162*b1cdbd2cSJim Jagielski if( m_nReadCount == 0 ) 163*b1cdbd2cSJim Jagielski { 164*b1cdbd2cSJim Jagielski m_aWriteCondition.set(); 165*b1cdbd2cSJim Jagielski } 166*b1cdbd2cSJim Jagielski } 167*b1cdbd2cSJim Jagielski 168*b1cdbd2cSJim Jagielski /*-****************************************************************************************************//** 169*b1cdbd2cSJim Jagielski @interface IRWLock 170*b1cdbd2cSJim Jagielski @short set lock for writing 171*b1cdbd2cSJim Jagielski @descr A guard should call this method to acquire write access on your member. 172*b1cdbd2cSJim Jagielski Reading is allowed too - of course. 173*b1cdbd2cSJim Jagielski After successfully calling of this method you are the only writer. 174*b1cdbd2cSJim Jagielski 175*b1cdbd2cSJim Jagielski @seealso method releaseWriteAccess() 176*b1cdbd2cSJim Jagielski 177*b1cdbd2cSJim Jagielski @param - 178*b1cdbd2cSJim Jagielski @return - 179*b1cdbd2cSJim Jagielski 180*b1cdbd2cSJim Jagielski @onerror - 181*b1cdbd2cSJim Jagielski *//*-*****************************************************************************************************/ acquireWriteAccess()182*b1cdbd2cSJim Jagielski inline virtual void acquireWriteAccess() 183*b1cdbd2cSJim Jagielski { 184*b1cdbd2cSJim Jagielski // You have to stand in our serialize-queue till all reader 185*b1cdbd2cSJim Jagielski // are registered (not for releasing them!) or writer finished their work! 186*b1cdbd2cSJim Jagielski // Don't use a guard to do so - because you must hold the mutex till 187*b1cdbd2cSJim Jagielski // you call releaseWriteAccess()! 188*b1cdbd2cSJim Jagielski // After succesfull acquire you have to wait for current working reader. 189*b1cdbd2cSJim Jagielski // Used condition will open by last gone reader object. 190*b1cdbd2cSJim Jagielski m_aSerializer.acquire(); 191*b1cdbd2cSJim Jagielski m_aWriteCondition.wait(); 192*b1cdbd2cSJim Jagielski 193*b1cdbd2cSJim Jagielski #ifdef ENABLE_MUTEXDEBUG 194*b1cdbd2cSJim Jagielski // A writer is an exclusiv accessor! 195*b1cdbd2cSJim Jagielski LOG_ASSERT2( m_nReadCount!=0, "FairRWLock::acquireWriteAccess()", "No threadsafe code detected ... : Read count != 0!" ) 196*b1cdbd2cSJim Jagielski #endif 197*b1cdbd2cSJim Jagielski } 198*b1cdbd2cSJim Jagielski 199*b1cdbd2cSJim Jagielski /*-****************************************************************************************************//** 200*b1cdbd2cSJim Jagielski @interface IRWLock 201*b1cdbd2cSJim Jagielski @short reset lock for writing 202*b1cdbd2cSJim Jagielski @descr A guard should call this method to release write access on your member. 203*b1cdbd2cSJim Jagielski 204*b1cdbd2cSJim Jagielski @seealso method acquireWriteAccess() 205*b1cdbd2cSJim Jagielski 206*b1cdbd2cSJim Jagielski @param - 207*b1cdbd2cSJim Jagielski @return - 208*b1cdbd2cSJim Jagielski 209*b1cdbd2cSJim Jagielski @onerror - 210*b1cdbd2cSJim Jagielski *//*-*****************************************************************************************************/ releaseWriteAccess()211*b1cdbd2cSJim Jagielski inline virtual void releaseWriteAccess() 212*b1cdbd2cSJim Jagielski { 213*b1cdbd2cSJim Jagielski // The only one you have to do here is to release 214*b1cdbd2cSJim Jagielski // hold seriliaze-mutex. All other user of these instance are blocked 215*b1cdbd2cSJim Jagielski // by these mutex! 216*b1cdbd2cSJim Jagielski // You don't need any other mutex here - you are the only one in the moment! 217*b1cdbd2cSJim Jagielski 218*b1cdbd2cSJim Jagielski #ifdef ENABLE_MUTEXDEBUG 219*b1cdbd2cSJim Jagielski // A writer is an exclusiv accessor! 220*b1cdbd2cSJim Jagielski LOG_ASSERT2( m_nReadCount!=0, "FairRWLock::releaseWriteAccess()", "No threadsafe code detected ... : Read count != 0!" ) 221*b1cdbd2cSJim Jagielski #endif 222*b1cdbd2cSJim Jagielski 223*b1cdbd2cSJim Jagielski m_aSerializer.release(); 224*b1cdbd2cSJim Jagielski } 225*b1cdbd2cSJim Jagielski 226*b1cdbd2cSJim Jagielski /*-****************************************************************************************************//** 227*b1cdbd2cSJim Jagielski @interface IRWLock 228*b1cdbd2cSJim Jagielski @short downgrade a write access to a read access 229*b1cdbd2cSJim Jagielski @descr A guard should call this method to change a write to a read access. 230*b1cdbd2cSJim Jagielski New readers can work too - new writer are blocked! 231*b1cdbd2cSJim Jagielski 232*b1cdbd2cSJim Jagielski @attention Don't call this method if you are not a writer! 233*b1cdbd2cSJim Jagielski Results are not defined then ... 234*b1cdbd2cSJim Jagielski An upgrade can't be implemented realy ... because acquiring new access 235*b1cdbd2cSJim Jagielski will be the same - there no differences! 236*b1cdbd2cSJim Jagielski 237*b1cdbd2cSJim Jagielski @seealso - 238*b1cdbd2cSJim Jagielski 239*b1cdbd2cSJim Jagielski @param - 240*b1cdbd2cSJim Jagielski @return - 241*b1cdbd2cSJim Jagielski 242*b1cdbd2cSJim Jagielski @onerror - 243*b1cdbd2cSJim Jagielski *//*-*****************************************************************************************************/ downgradeWriteAccess()244*b1cdbd2cSJim Jagielski inline virtual void downgradeWriteAccess() 245*b1cdbd2cSJim Jagielski { 246*b1cdbd2cSJim Jagielski // You must be a writer to call this method! 247*b1cdbd2cSJim Jagielski // We can't check it - but otherwise it's your problem ... 248*b1cdbd2cSJim Jagielski // Thats why you don't need any mutex here. 249*b1cdbd2cSJim Jagielski 250*b1cdbd2cSJim Jagielski #ifdef ENABLE_MUTEXDEBUG 251*b1cdbd2cSJim Jagielski // A writer is an exclusiv accessor! 252*b1cdbd2cSJim Jagielski LOG_ASSERT2( m_nReadCount!=0, "FairRWLock::downgradeWriteAccess()", "No threadsafe code detected ... : Read count != 0!" ) 253*b1cdbd2cSJim Jagielski #endif 254*b1cdbd2cSJim Jagielski 255*b1cdbd2cSJim Jagielski // Register himself as "new" reader. 256*b1cdbd2cSJim Jagielski // This value must be 0 before - because we support single writer access only! 257*b1cdbd2cSJim Jagielski ++m_nReadCount; 258*b1cdbd2cSJim Jagielski // Close barrier for other writer! 259*b1cdbd2cSJim Jagielski // Why? 260*b1cdbd2cSJim Jagielski // You hold the serializer mutex - next one can be a reader OR a writer. 261*b1cdbd2cSJim Jagielski // They must blocked then - because you will be a reader after this call 262*b1cdbd2cSJim Jagielski // and writer use this condition to wait for current reader! 263*b1cdbd2cSJim Jagielski m_aWriteCondition.reset(); 264*b1cdbd2cSJim Jagielski // Open door for next waiting thread in serialize queue! 265*b1cdbd2cSJim Jagielski m_aSerializer.release(); 266*b1cdbd2cSJim Jagielski } 267*b1cdbd2cSJim Jagielski 268*b1cdbd2cSJim Jagielski //------------------------------------------------------------------------------------------------------------- 269*b1cdbd2cSJim Jagielski // private member 270*b1cdbd2cSJim Jagielski //------------------------------------------------------------------------------------------------------------- 271*b1cdbd2cSJim Jagielski private: 272*b1cdbd2cSJim Jagielski 273*b1cdbd2cSJim Jagielski ::osl::Mutex m_aAccessLock ; /// regulate access on internal member of this instance 274*b1cdbd2cSJim Jagielski ::osl::Mutex m_aSerializer ; /// serialze incoming read/write access threads 275*b1cdbd2cSJim Jagielski ::osl::Condition m_aWriteCondition ; /// a writer must wait till current working reader are gone 276*b1cdbd2cSJim Jagielski sal_Int32 m_nReadCount ; /// every reader is registered - the last one open the door for waiting writer 277*b1cdbd2cSJim Jagielski 278*b1cdbd2cSJim Jagielski }; // class FairRWLock 279*b1cdbd2cSJim Jagielski 280*b1cdbd2cSJim Jagielski } // namespace framework 281*b1cdbd2cSJim Jagielski 282*b1cdbd2cSJim Jagielski #endif // #ifndef __FRAMEWORK_THREADHELP_FAIRRWLOCK_HXX_ 283