1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: lockhelper.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_framework.hxx"
34 //_________________________________________________________________________________________________________________
36 //_________________________________________________________________________________________________________________
37 #include <threadhelp/lockhelper.hxx>
39 #include <macros/debug.hxx>
41 #include <macros/generic.hxx>
43 //_________________________________________________________________________________________________________________
45 //_________________________________________________________________________________________________________________
47 //_________________________________________________________________________________________________________________
49 //_________________________________________________________________________________________________________________
50 #include <vos/process.hxx>
52 //_________________________________________________________________________________________________________________
54 //_________________________________________________________________________________________________________________
58 //_________________________________________________________________________________________________________________
60 //_________________________________________________________________________________________________________________
62 //_________________________________________________________________________________________________________________
64 //_________________________________________________________________________________________________________________
66 /*-************************************************************************************************************//**
67 @short use ctor to initialize instance
68 @descr We must initialize our member "m_eLockType". This value specify handling of locking.
69 User use this helper as parameter for a guard creation.
70 These guard use "m_eLockType" to set lock in the right way by using right mutex or rw-lock.
72 @seealso enum ELockType
73 @seealso class ReadGuard
74 @seealso class WriteGuard
76 @param "rSolarMutex", for some components we must be "vcl-free"! So we can't work with our solar mutex
77 directly. User must set his reference at this instance - so we can work with it!
81 *//*-*************************************************************************************************************/
82 LockHelper::LockHelper( ::vos::IMutex
* pSolarMutex
)
83 : m_pFairRWLock ( NULL
)
84 , m_pOwnMutex ( NULL
)
85 , m_pSolarMutex ( NULL
)
86 , m_pShareableOslMutex( NULL
)
87 , m_bDummySolarMutex ( sal_False
)
89 m_eLockType
= implts_getLockType();
92 case E_NOTHING
: break; // There is nothing to do ...
94 m_pOwnMutex
= new ::osl::Mutex
;
98 if( pSolarMutex
== NULL
)
100 m_pSolarMutex
= new ::vos::OMutex
;
101 m_bDummySolarMutex
= sal_True
;
105 m_pSolarMutex
= pSolarMutex
;
109 case E_FAIRRWLOCK
: {
110 m_pFairRWLock
= new FairRWLock
;
113 #ifdef ENABLE_ASSERTIONS
114 default : LOG_ASSERT2( m_eLockType
!=E_NOTHING
, "LockHelper::ctor()", "Invalid lock type found .. so code will not be threadsafe!" )
119 /*-************************************************************************************************************//**
120 @short default dtor to release safed pointer
121 @descr We have created dynamical mutex- or lock-member ... or we hold a pointer to external objects.
130 *//*-*************************************************************************************************************/
131 LockHelper::~LockHelper()
133 if( m_pShareableOslMutex
!= NULL
)
135 // Sometimes we hold two pointer to same object!
136 // (e.g. if m_eLockType==E_OWNMUTEX!)
137 // So we should forget it ... but don't delete it twice!
138 if( m_pShareableOslMutex
!= m_pOwnMutex
)
140 delete m_pShareableOslMutex
;
142 m_pShareableOslMutex
= NULL
;
144 if( m_pOwnMutex
!= NULL
)
149 if( m_pSolarMutex
!= NULL
)
151 if (m_bDummySolarMutex
)
153 delete static_cast<vos::OMutex
*>(m_pSolarMutex
);
154 m_bDummySolarMutex
= sal_False
;
156 m_pSolarMutex
= NULL
;
158 if( m_pFairRWLock
!= NULL
)
160 delete m_pFairRWLock
;
161 m_pFairRWLock
= NULL
;
165 /*-************************************************************************************************************//**
167 @short set an exclusiv lock
168 @descr We must match this lock call with current set lock type and used lock member.
169 If a mutex should be used - it will be easy ... but if a rw-lock should be used
170 we must simulate it as a write access!
172 @attention If a shareable osl mutex exist, he must be used as twice!
173 It's neccessary for some cppu-helper classes ...
175 @seealso method acquireWriteAccess()
181 *//*-*************************************************************************************************************/
182 void LockHelper::acquire()
184 switch( m_eLockType
)
186 case E_NOTHING
: break; // There is nothing to do ...
188 m_pOwnMutex
->acquire();
191 case E_SOLARMUTEX
: {
192 m_pSolarMutex
->acquire();
195 case E_FAIRRWLOCK
: {
196 m_pFairRWLock
->acquireWriteAccess();
202 /*-************************************************************************************************************//**
204 @short release exclusiv lock
205 @descr We must match this unlock call with current set lock type and used lock member.
206 If a mutex should be used - it will be easy ... but if a rw-lock should be used
207 we must simulate it as a write access!
209 @attention If a shareable osl mutex exist, he must be used as twice!
210 It's neccessary for some cppu-helper classes ...
212 @seealso method releaseWriteAccess()
218 *//*-*************************************************************************************************************/
219 void LockHelper::release()
221 switch( m_eLockType
)
223 case E_NOTHING
: break; // There is nothing to do ...
225 m_pOwnMutex
->release();
228 case E_SOLARMUTEX
: {
229 m_pSolarMutex
->release();
232 case E_FAIRRWLOCK
: {
233 m_pFairRWLock
->releaseWriteAccess();
239 /*-************************************************************************************************************//**
241 @short set lock for reading
242 @descr A guard should call this method to acquire read access on your member.
243 Writing isn't allowed then - but nobody could check it for you!
244 We use m_eLockType to differ between all possible "lock-member"!!!
246 @attention If a shareable osl mutex exist, he must be used as twice!
247 It's neccessary for some cppu-helper classes ...
249 @seealso method releaseReadAccess()
255 *//*-*************************************************************************************************************/
256 void LockHelper::acquireReadAccess()
258 switch( m_eLockType
)
260 case E_NOTHING
: break; // There is nothing to do ...
262 m_pOwnMutex
->acquire();
265 case E_SOLARMUTEX
: {
266 m_pSolarMutex
->acquire();
269 case E_FAIRRWLOCK
: {
270 m_pFairRWLock
->acquireReadAccess();
276 /*-************************************************************************************************************//**
278 @short reset lock for reading
279 @descr A guard should call this method to release read access on your member.
280 We use m_eLockType to differ between all possible "lock-member"!!!
282 @attention If a shareable osl mutex exist, he must be used as twice!
283 It's neccessary for some cppu-helper classes ...
285 @seealso method acquireReadAccess()
291 *//*-*************************************************************************************************************/
292 void LockHelper::releaseReadAccess()
294 switch( m_eLockType
)
296 case E_NOTHING
: break; // There is nothing to do ...
298 m_pOwnMutex
->release();
301 case E_SOLARMUTEX
: {
302 m_pSolarMutex
->release();
305 case E_FAIRRWLOCK
: {
306 m_pFairRWLock
->releaseReadAccess();
312 /*-************************************************************************************************************//**
314 @short set lock for writing
315 @descr A guard should call this method to acquire write access on your member.
316 Reading is allowed too - of course.
317 After successfully calling of this method you are the only writer.
318 We use m_eLockType to differ between all possible "lock-member"!!!
320 @attention If a shareable osl mutex exist, he must be used as twice!
321 It's neccessary for some cppu-helper classes ...
323 @seealso method releaseWriteAccess()
329 *//*-*************************************************************************************************************/
330 void LockHelper::acquireWriteAccess()
332 switch( m_eLockType
)
334 case E_NOTHING
: break; // There is nothing to do ...
336 m_pOwnMutex
->acquire();
339 case E_SOLARMUTEX
: {
340 m_pSolarMutex
->acquire();
343 case E_FAIRRWLOCK
: {
344 m_pFairRWLock
->acquireWriteAccess();
350 /*-************************************************************************************************************//**
352 @short reset lock for writing
353 @descr A guard should call this method to release write access on your member.
354 We use m_eLockType to differ between all possible "lock-member"!!!
356 @attention If a shareable osl mutex exist, he must be used as twice!
357 It's neccessary for some cppu-helper classes ...
359 @seealso method acquireWriteAccess()
365 *//*-*************************************************************************************************************/
366 void LockHelper::releaseWriteAccess()
368 switch( m_eLockType
)
370 case E_NOTHING
: break; // There is nothing to do ...
372 m_pOwnMutex
->release();
375 case E_SOLARMUTEX
: {
376 m_pSolarMutex
->release();
379 case E_FAIRRWLOCK
: {
380 m_pFairRWLock
->releaseWriteAccess();
386 /*-************************************************************************************************************//**
388 @short downgrade a write access to a read access
389 @descr A guard should call this method to change a write to a read access.
390 New readers can work too - new writer are blocked!
391 We use m_eLockType to differ between all possible "lock-member"!!!
393 @attention Ignore shareable mutex(!) - because this call never should release a lock completly!
394 We change a write access to a read access only.
396 @attention a) Don't call this method if you are not a writer!
397 Results are not defined then ...
398 An upgrade can't be implemented realy ... because acquiring new access
399 will be the same - there no differences!
400 b) Without function if m_eLockTyp is different from E_FAIRRWLOCK(!) ...
401 because, a mutex don't support it realy.
409 *//*-*************************************************************************************************************/
410 void LockHelper::downgradeWriteAccess()
412 switch( m_eLockType
)
414 case E_NOTHING
: break; // There is nothing to do ...
415 case E_OWNMUTEX
: break; // Not supported for mutex!
416 case E_SOLARMUTEX
: break; // Not supported for mutex!
417 case E_FAIRRWLOCK
: m_pFairRWLock
->downgradeWriteAccess();
422 /*-************************************************************************************************************//**
423 @short return a reference to a static lock helper
424 @descr Sometimes we need the global mutex or rw-lock! (e.g. in our own static methods)
425 But it's not a good idea to use these global one very often ...
426 Thats why we use this little helper method.
427 We create our own "class global static" lock.
428 It will be created at first call only!
429 All other requests use these created one then directly.
434 @return A reference to a static mutex/lock member.
436 @onerror No error should occure.
437 *//*-*************************************************************************************************************/
438 LockHelper
& LockHelper::getGlobalLock( ::vos::IMutex
* pSolarMutex
)
440 // Initialize static "member" only for one time!
442 // a) Start with an invalid lock (NULL pointer)
443 // b) If these method first called (lock not already exist!) ...
444 // c) ... we must create a new one. Protect follow code with the global mutex -
445 // (It must be - we create a static variable!)
446 // d) Check pointer again - because ... another instance of our class could be faster then these one!
447 // e) Create the new lock and set it for return on static variable.
448 // f) Return new created or already existing lock object.
449 static LockHelper
* pLock
= NULL
;
452 ::osl::MutexGuard
aGuard( ::osl::Mutex::getGlobalMutex() );
455 static LockHelper
aLock( pSolarMutex
);
462 /*-************************************************************************************************************//**
463 @short return a reference to shared mutex member
464 @descr Sometimes we need a osl-mutex for sharing with our uno helper ...
466 a) If we have an initialized "own mutex" ... we can use it!
467 b) Otherwhise we must use a different mutex member :-(
473 @return A reference to a shared mutex.
475 @onerror No error should occure.
476 *//*-*************************************************************************************************************/
477 ::osl::Mutex
& LockHelper::getShareableOslMutex()
479 if( m_pShareableOslMutex
== NULL
)
481 ::osl::MutexGuard
aGuard( ::osl::Mutex::getGlobalMutex() );
482 if( m_pShareableOslMutex
== NULL
)
484 switch( m_eLockType
)
487 m_pShareableOslMutex
= m_pOwnMutex
;
491 m_pShareableOslMutex
= new ::osl::Mutex
;
497 return *m_pShareableOslMutex
;
500 /*-************************************************************************************************************//**
501 @short search for right lock type, which should be used by an instance of this struct
502 @descr We must initialize our member "m_eLockType". This value specify handling of locking.
503 How we can do that? We search for an environment variable. We do it only for one time ....
504 because the environment is fix. So we safe this value and use it for all further requests.
505 If no variable could be found - we use a fallback!
507 @attention We have numbered all our enum values for ELockType. So we can use it as value of searched
508 environment variable too!
510 @seealso enum ELockType
511 @seealso environment LOCKTYPE
514 @return A reference to a created and right initialized lock type!
516 @onerror We use a fallback!
517 *//*-*************************************************************************************************************/
518 ELockType
& LockHelper::implts_getLockType()
520 // Initialize static "member" only for one time!
522 // a) Start with an invalid variable (NULL pointer)
523 // b) If these method first called (value not already exist!) ...
524 // c) ... we must create a new one. Protect follow code with the global mutex -
525 // (It must be - we create a static variable!)
526 // d) Check pointer again - because ... another instance of our class could be faster then these one!
527 // e) Create the new static variable, get value from the environment and set it
528 // f) Return new created or already existing static variable.
529 static ELockType
* pType
= NULL
;
532 ::osl::MutexGuard
aGuard( ::osl::Mutex::getGlobalMutex() );
535 static ELockType eType
= FALLBACK_LOCKTYPE
;
537 ::vos::OStartupInfo aEnvironment
;
538 ::rtl::OUString sValue
;
539 if( aEnvironment
.getEnvironment( ENVVAR_LOCKTYPE
, sValue
) == ::vos::OStartupInfo::E_None
)
541 eType
= (ELockType
)(sValue
.toInt32());
544 LOG_LOCKTYPE( FALLBACK_LOCKTYPE
, eType
)
552 } // namespace framework