1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_framework.hxx" 26 27 //_________________________________________________________________________________________________________________ 28 // my own includes 29 //_________________________________________________________________________________________________________________ 30 #include <threadhelp/lockhelper.hxx> 31 #include <general.h> 32 #include <macros/debug.hxx> 33 34 #include <macros/generic.hxx> 35 36 //_________________________________________________________________________________________________________________ 37 // interface includes 38 //_________________________________________________________________________________________________________________ 39 40 //_________________________________________________________________________________________________________________ 41 // other includes 42 //_________________________________________________________________________________________________________________ 43 #include <vos/process.hxx> 44 45 //_________________________________________________________________________________________________________________ 46 // namespace 47 //_________________________________________________________________________________________________________________ 48 49 namespace framework{ 50 51 //_________________________________________________________________________________________________________________ 52 // const 53 //_________________________________________________________________________________________________________________ 54 55 //_________________________________________________________________________________________________________________ 56 // declarations 57 //_________________________________________________________________________________________________________________ 58 59 /*-************************************************************************************************************//** 60 @short use ctor to initialize instance 61 @descr We must initialize our member "m_eLockType". This value specify handling of locking. 62 User use this helper as parameter for a guard creation. 63 These guard use "m_eLockType" to set lock in the right way by using right mutex or rw-lock. 64 65 @seealso enum ELockType 66 @seealso class ReadGuard 67 @seealso class WriteGuard 68 69 @param "rSolarMutex", for some components we must be "vcl-free"! So we can't work with our solar mutex 70 directly. User must set his reference at this instance - so we can work with it! 71 @return - 72 73 @onerror - 74 *//*-*************************************************************************************************************/ 75 LockHelper::LockHelper( ::vos::IMutex* pSolarMutex ) 76 : m_pFairRWLock ( NULL ) 77 , m_pOwnMutex ( NULL ) 78 , m_pSolarMutex ( NULL ) 79 , m_pShareableOslMutex( NULL ) 80 , m_bDummySolarMutex ( sal_False ) 81 { 82 m_eLockType = implts_getLockType(); 83 switch( m_eLockType ) 84 { 85 case E_NOTHING : break; // There is nothing to do ... 86 case E_OWNMUTEX : { 87 m_pOwnMutex = new ::osl::Mutex; 88 } 89 break; 90 case E_SOLARMUTEX : { 91 if( pSolarMutex == NULL ) 92 { 93 m_pSolarMutex = new ::vos::OMutex; 94 m_bDummySolarMutex = sal_True; 95 } 96 else 97 { 98 m_pSolarMutex = pSolarMutex; 99 } 100 } 101 break; 102 case E_FAIRRWLOCK : { 103 m_pFairRWLock = new FairRWLock; 104 } 105 break; 106 #ifdef ENABLE_ASSERTIONS 107 default : LOG_ASSERT2( m_eLockType!=E_NOTHING, "LockHelper::ctor()", "Invalid lock type found .. so code will not be threadsafe!" ) 108 #endif 109 } 110 } 111 112 /*-************************************************************************************************************//** 113 @short default dtor to release safed pointer 114 @descr We have created dynamical mutex- or lock-member ... or we hold a pointer to external objects. 115 We must release it! 116 117 @seealso ctor() 118 119 @param - 120 @return - 121 122 @onerror - 123 *//*-*************************************************************************************************************/ 124 LockHelper::~LockHelper() 125 { 126 if( m_pShareableOslMutex != NULL ) 127 { 128 // Sometimes we hold two pointer to same object! 129 // (e.g. if m_eLockType==E_OWNMUTEX!) 130 // So we should forget it ... but don't delete it twice! 131 if( m_pShareableOslMutex != m_pOwnMutex ) 132 { 133 delete m_pShareableOslMutex; 134 } 135 m_pShareableOslMutex = NULL; 136 } 137 if( m_pOwnMutex != NULL ) 138 { 139 delete m_pOwnMutex; 140 m_pOwnMutex = NULL; 141 } 142 if( m_pSolarMutex != NULL ) 143 { 144 if (m_bDummySolarMutex) 145 { 146 delete static_cast<vos::OMutex*>(m_pSolarMutex); 147 m_bDummySolarMutex = sal_False; 148 } 149 m_pSolarMutex = NULL; 150 } 151 if( m_pFairRWLock != NULL ) 152 { 153 delete m_pFairRWLock; 154 m_pFairRWLock = NULL; 155 } 156 } 157 158 /*-************************************************************************************************************//** 159 @interface IMutex 160 @short set an exclusiv lock 161 @descr We must match this lock call with current set lock type and used lock member. 162 If a mutex should be used - it will be easy ... but if a rw-lock should be used 163 we must simulate it as a write access! 164 165 @attention If a shareable osl mutex exist, he must be used as twice! 166 It's necessary for some cppu-helper classes ... 167 168 @seealso method acquireWriteAccess() 169 170 @param - 171 @return - 172 173 @onerror - 174 *//*-*************************************************************************************************************/ 175 void LockHelper::acquire() 176 { 177 switch( m_eLockType ) 178 { 179 case E_NOTHING : break; // There is nothing to do ... 180 case E_OWNMUTEX : { 181 m_pOwnMutex->acquire(); 182 } 183 break; 184 case E_SOLARMUTEX : { 185 m_pSolarMutex->acquire(); 186 } 187 break; 188 case E_FAIRRWLOCK : { 189 m_pFairRWLock->acquireWriteAccess(); 190 } 191 break; 192 } 193 } 194 195 /*-************************************************************************************************************//** 196 @interface IMutex 197 @short release exclusiv lock 198 @descr We must match this unlock call with current set lock type and used lock member. 199 If a mutex should be used - it will be easy ... but if a rw-lock should be used 200 we must simulate it as a write access! 201 202 @attention If a shareable osl mutex exist, he must be used as twice! 203 It's necessary for some cppu-helper classes ... 204 205 @seealso method releaseWriteAccess() 206 207 @param - 208 @return - 209 210 @onerror - 211 *//*-*************************************************************************************************************/ 212 void LockHelper::release() 213 { 214 switch( m_eLockType ) 215 { 216 case E_NOTHING : break; // There is nothing to do ... 217 case E_OWNMUTEX : { 218 m_pOwnMutex->release(); 219 } 220 break; 221 case E_SOLARMUTEX : { 222 m_pSolarMutex->release(); 223 } 224 break; 225 case E_FAIRRWLOCK : { 226 m_pFairRWLock->releaseWriteAccess(); 227 } 228 break; 229 } 230 } 231 232 /*-************************************************************************************************************//** 233 @interface IRWLock 234 @short set lock for reading 235 @descr A guard should call this method to acquire read access on your member. 236 Writing isn't allowed then - but nobody could check it for you! 237 We use m_eLockType to differ between all possible "lock-member"!!! 238 239 @attention If a shareable osl mutex exist, he must be used as twice! 240 It's necessary for some cppu-helper classes ... 241 242 @seealso method releaseReadAccess() 243 244 @param - 245 @return - 246 247 @onerror - 248 *//*-*************************************************************************************************************/ 249 void LockHelper::acquireReadAccess() 250 { 251 switch( m_eLockType ) 252 { 253 case E_NOTHING : break; // There is nothing to do ... 254 case E_OWNMUTEX : { 255 m_pOwnMutex->acquire(); 256 } 257 break; 258 case E_SOLARMUTEX : { 259 m_pSolarMutex->acquire(); 260 } 261 break; 262 case E_FAIRRWLOCK : { 263 m_pFairRWLock->acquireReadAccess(); 264 } 265 break; 266 } 267 } 268 269 /*-************************************************************************************************************//** 270 @interface IRWLock 271 @short reset lock for reading 272 @descr A guard should call this method to release read access on your member. 273 We use m_eLockType to differ between all possible "lock-member"!!! 274 275 @attention If a shareable osl mutex exist, he must be used as twice! 276 It's necessary for some cppu-helper classes ... 277 278 @seealso method acquireReadAccess() 279 280 @param - 281 @return - 282 283 @onerror - 284 *//*-*************************************************************************************************************/ 285 void LockHelper::releaseReadAccess() 286 { 287 switch( m_eLockType ) 288 { 289 case E_NOTHING : break; // There is nothing to do ... 290 case E_OWNMUTEX : { 291 m_pOwnMutex->release(); 292 } 293 break; 294 case E_SOLARMUTEX : { 295 m_pSolarMutex->release(); 296 } 297 break; 298 case E_FAIRRWLOCK : { 299 m_pFairRWLock->releaseReadAccess(); 300 } 301 break; 302 } 303 } 304 305 /*-************************************************************************************************************//** 306 @interface IRWLock 307 @short set lock for writing 308 @descr A guard should call this method to acquire write access on your member. 309 Reading is allowed too - of course. 310 After successfully calling of this method you are the only writer. 311 We use m_eLockType to differ between all possible "lock-member"!!! 312 313 @attention If a shareable osl mutex exist, he must be used as twice! 314 It's necessary for some cppu-helper classes ... 315 316 @seealso method releaseWriteAccess() 317 318 @param - 319 @return - 320 321 @onerror - 322 *//*-*************************************************************************************************************/ 323 void LockHelper::acquireWriteAccess() 324 { 325 switch( m_eLockType ) 326 { 327 case E_NOTHING : break; // There is nothing to do ... 328 case E_OWNMUTEX : { 329 m_pOwnMutex->acquire(); 330 } 331 break; 332 case E_SOLARMUTEX : { 333 m_pSolarMutex->acquire(); 334 } 335 break; 336 case E_FAIRRWLOCK : { 337 m_pFairRWLock->acquireWriteAccess(); 338 } 339 break; 340 } 341 } 342 343 /*-************************************************************************************************************//** 344 @interface IRWLock 345 @short reset lock for writing 346 @descr A guard should call this method to release write access on your member. 347 We use m_eLockType to differ between all possible "lock-member"!!! 348 349 @attention If a shareable osl mutex exist, he must be used as twice! 350 It's necessary for some cppu-helper classes ... 351 352 @seealso method acquireWriteAccess() 353 354 @param - 355 @return - 356 357 @onerror - 358 *//*-*************************************************************************************************************/ 359 void LockHelper::releaseWriteAccess() 360 { 361 switch( m_eLockType ) 362 { 363 case E_NOTHING : break; // There is nothing to do ... 364 case E_OWNMUTEX : { 365 m_pOwnMutex->release(); 366 } 367 break; 368 case E_SOLARMUTEX : { 369 m_pSolarMutex->release(); 370 } 371 break; 372 case E_FAIRRWLOCK : { 373 m_pFairRWLock->releaseWriteAccess(); 374 } 375 break; 376 } 377 } 378 379 /*-************************************************************************************************************//** 380 @interface IRWLock 381 @short downgrade a write access to a read access 382 @descr A guard should call this method to change a write to a read access. 383 New readers can work too - new writer are blocked! 384 We use m_eLockType to differ between all possible "lock-member"!!! 385 386 @attention Ignore shareable mutex(!) - because this call never should release a lock completly! 387 We change a write access to a read access only. 388 389 @attention a) Don't call this method if you are not a writer! 390 Results are not defined then ... 391 An upgrade can't be implemented really ... because acquiring new access 392 will be the same - there no differences! 393 b) Without function if m_eLockTyp is different from E_FAIRRWLOCK(!) ... 394 because, a mutex don't support it really. 395 396 @seealso - 397 398 @param - 399 @return - 400 401 @onerror - 402 *//*-*************************************************************************************************************/ 403 void LockHelper::downgradeWriteAccess() 404 { 405 switch( m_eLockType ) 406 { 407 case E_NOTHING : break; // There is nothing to do ... 408 case E_OWNMUTEX : break; // Not supported for mutex! 409 case E_SOLARMUTEX : break; // Not supported for mutex! 410 case E_FAIRRWLOCK : m_pFairRWLock->downgradeWriteAccess(); 411 break; 412 } 413 } 414 415 /*-************************************************************************************************************//** 416 @short return a reference to a static lock helper 417 @descr Sometimes we need the global mutex or rw-lock! (e.g. in our own static methods) 418 But it's not a good idea to use these global one very often ... 419 That's why we use this little helper method. 420 We create our own "class global static" lock. 421 It will be created at first call only! 422 All other requests use these created one then directly. 423 424 @seealso - 425 426 @param - 427 @return A reference to a static mutex/lock member. 428 429 @onerror No error should occur. 430 *//*-*************************************************************************************************************/ 431 LockHelper& LockHelper::getGlobalLock( ::vos::IMutex* pSolarMutex ) 432 { 433 // Initialize static "member" only for one time! 434 // Algorithm: 435 // a) Start with an invalid lock (NULL pointer) 436 // b) If these method first called (lock not already exist!) ... 437 // c) ... we must create a new one. Protect follow code with the global mutex - 438 // (It must be - we create a static variable!) 439 // d) Check pointer again - because ... another instance of our class could be faster then these one! 440 // e) Create the new lock and set it for return on static variable. 441 // f) Return new created or already existing lock object. 442 static LockHelper* pLock = NULL; 443 if( pLock == NULL ) 444 { 445 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); 446 if( pLock == NULL ) 447 { 448 static LockHelper aLock( pSolarMutex ); 449 pLock = &aLock; 450 } 451 } 452 return *pLock; 453 } 454 455 /*-************************************************************************************************************//** 456 @short return a reference to shared mutex member 457 @descr Sometimes we need a osl-mutex for sharing with our uno helper ... 458 What can we do? 459 a) If we have an initialized "own mutex" ... we can use it! 460 b) Otherwise we must use a different mutex member :-( 461 I HOPE IT WORKS! 462 463 @seealso - 464 465 @param - 466 @return A reference to a shared mutex. 467 468 @onerror No error should occur. 469 *//*-*************************************************************************************************************/ 470 ::osl::Mutex& LockHelper::getShareableOslMutex() 471 { 472 if( m_pShareableOslMutex == NULL ) 473 { 474 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); 475 if( m_pShareableOslMutex == NULL ) 476 { 477 switch( m_eLockType ) 478 { 479 case E_OWNMUTEX : { 480 m_pShareableOslMutex = m_pOwnMutex; 481 } 482 break; 483 default : { 484 m_pShareableOslMutex = new ::osl::Mutex; 485 } 486 break; 487 } 488 } 489 } 490 return *m_pShareableOslMutex; 491 } 492 493 /*-************************************************************************************************************//** 494 @short search for right lock type, which should be used by an instance of this struct 495 @descr We must initialize our member "m_eLockType". This value specify handling of locking. 496 How we can do that? We search for an environment variable. We do it only for one time .... 497 because the environment is fix. So we safe this value and use it for all further requests. 498 If no variable could be found - we use a fallback! 499 500 @attention We have numbered all our enum values for ELockType. So we can use it as value of searched 501 environment variable too! 502 503 @seealso enum ELockType 504 @seealso environment LOCKTYPE 505 506 @param - 507 @return A reference to a created and right initialized lock type! 508 509 @onerror We use a fallback! 510 *//*-*************************************************************************************************************/ 511 ELockType& LockHelper::implts_getLockType() 512 { 513 // Initialize static "member" only for one time! 514 // Algorithm: 515 // a) Start with an invalid variable (NULL pointer) 516 // b) If these method first called (value not already exist!) ... 517 // c) ... we must create a new one. Protect follow code with the global mutex - 518 // (It must be - we create a static variable!) 519 // d) Check pointer again - because ... another instance of our class could be faster then these one! 520 // e) Create the new static variable, get value from the environment and set it 521 // f) Return new created or already existing static variable. 522 static ELockType* pType = NULL; 523 if( pType == NULL ) 524 { 525 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); 526 if( pType == NULL ) 527 { 528 static ELockType eType = FALLBACK_LOCKTYPE; 529 530 ::vos::OStartupInfo aEnvironment; 531 ::rtl::OUString sValue ; 532 if( aEnvironment.getEnvironment( ENVVAR_LOCKTYPE, sValue ) == ::vos::OStartupInfo::E_None ) 533 { 534 eType = (ELockType)(sValue.toInt32()); 535 } 536 537 LOG_LOCKTYPE( FALLBACK_LOCKTYPE, eType ) 538 539 pType = &eType; 540 } 541 } 542 return *pType; 543 } 544 545 } // namespace framework 546