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