1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
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.
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).
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.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_framework.hxx"
31 //_________________________________________________________________________________________________________________
33 //_________________________________________________________________________________________________________________
34 #include <threadhelp/lockhelper.hxx>
36 #include <macros/debug.hxx>
38 #include <macros/generic.hxx>
40 //_________________________________________________________________________________________________________________
42 //_________________________________________________________________________________________________________________
44 //_________________________________________________________________________________________________________________
46 //_________________________________________________________________________________________________________________
47 #include <vos/process.hxx>
49 //_________________________________________________________________________________________________________________
51 //_________________________________________________________________________________________________________________
55 //_________________________________________________________________________________________________________________
57 //_________________________________________________________________________________________________________________
59 //_________________________________________________________________________________________________________________
61 //_________________________________________________________________________________________________________________
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.
69 @seealso enum ELockType
70 @seealso class ReadGuard
71 @seealso class WriteGuard
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!
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
)
86 m_eLockType
= implts_getLockType();
89 case E_NOTHING
: break; // There is nothing to do ...
91 m_pOwnMutex
= new ::osl::Mutex
;
95 if( pSolarMutex
== NULL
)
97 m_pSolarMutex
= new ::vos::OMutex
;
98 m_bDummySolarMutex
= sal_True
;
102 m_pSolarMutex
= pSolarMutex
;
106 case E_FAIRRWLOCK
: {
107 m_pFairRWLock
= new FairRWLock
;
110 #ifdef ENABLE_ASSERTIONS
111 default : LOG_ASSERT2( m_eLockType
!=E_NOTHING
, "LockHelper::ctor()", "Invalid lock type found .. so code will not be threadsafe!" )
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.
127 *//*-*************************************************************************************************************/
128 LockHelper::~LockHelper()
130 if( m_pShareableOslMutex
!= NULL
)
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
)
137 delete m_pShareableOslMutex
;
139 m_pShareableOslMutex
= NULL
;
141 if( m_pOwnMutex
!= NULL
)
146 if( m_pSolarMutex
!= NULL
)
148 if (m_bDummySolarMutex
)
150 delete static_cast<vos::OMutex
*>(m_pSolarMutex
);
151 m_bDummySolarMutex
= sal_False
;
153 m_pSolarMutex
= NULL
;
155 if( m_pFairRWLock
!= NULL
)
157 delete m_pFairRWLock
;
158 m_pFairRWLock
= NULL
;
162 /*-************************************************************************************************************//**
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!
169 @attention If a shareable osl mutex exist, he must be used as twice!
170 It's neccessary for some cppu-helper classes ...
172 @seealso method acquireWriteAccess()
178 *//*-*************************************************************************************************************/
179 void LockHelper::acquire()
181 switch( m_eLockType
)
183 case E_NOTHING
: break; // There is nothing to do ...
185 m_pOwnMutex
->acquire();
188 case E_SOLARMUTEX
: {
189 m_pSolarMutex
->acquire();
192 case E_FAIRRWLOCK
: {
193 m_pFairRWLock
->acquireWriteAccess();
199 /*-************************************************************************************************************//**
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!
206 @attention If a shareable osl mutex exist, he must be used as twice!
207 It's neccessary for some cppu-helper classes ...
209 @seealso method releaseWriteAccess()
215 *//*-*************************************************************************************************************/
216 void LockHelper::release()
218 switch( m_eLockType
)
220 case E_NOTHING
: break; // There is nothing to do ...
222 m_pOwnMutex
->release();
225 case E_SOLARMUTEX
: {
226 m_pSolarMutex
->release();
229 case E_FAIRRWLOCK
: {
230 m_pFairRWLock
->releaseWriteAccess();
236 /*-************************************************************************************************************//**
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"!!!
243 @attention If a shareable osl mutex exist, he must be used as twice!
244 It's neccessary for some cppu-helper classes ...
246 @seealso method releaseReadAccess()
252 *//*-*************************************************************************************************************/
253 void LockHelper::acquireReadAccess()
255 switch( m_eLockType
)
257 case E_NOTHING
: break; // There is nothing to do ...
259 m_pOwnMutex
->acquire();
262 case E_SOLARMUTEX
: {
263 m_pSolarMutex
->acquire();
266 case E_FAIRRWLOCK
: {
267 m_pFairRWLock
->acquireReadAccess();
273 /*-************************************************************************************************************//**
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"!!!
279 @attention If a shareable osl mutex exist, he must be used as twice!
280 It's neccessary for some cppu-helper classes ...
282 @seealso method acquireReadAccess()
288 *//*-*************************************************************************************************************/
289 void LockHelper::releaseReadAccess()
291 switch( m_eLockType
)
293 case E_NOTHING
: break; // There is nothing to do ...
295 m_pOwnMutex
->release();
298 case E_SOLARMUTEX
: {
299 m_pSolarMutex
->release();
302 case E_FAIRRWLOCK
: {
303 m_pFairRWLock
->releaseReadAccess();
309 /*-************************************************************************************************************//**
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"!!!
317 @attention If a shareable osl mutex exist, he must be used as twice!
318 It's neccessary for some cppu-helper classes ...
320 @seealso method releaseWriteAccess()
326 *//*-*************************************************************************************************************/
327 void LockHelper::acquireWriteAccess()
329 switch( m_eLockType
)
331 case E_NOTHING
: break; // There is nothing to do ...
333 m_pOwnMutex
->acquire();
336 case E_SOLARMUTEX
: {
337 m_pSolarMutex
->acquire();
340 case E_FAIRRWLOCK
: {
341 m_pFairRWLock
->acquireWriteAccess();
347 /*-************************************************************************************************************//**
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"!!!
353 @attention If a shareable osl mutex exist, he must be used as twice!
354 It's neccessary for some cppu-helper classes ...
356 @seealso method acquireWriteAccess()
362 *//*-*************************************************************************************************************/
363 void LockHelper::releaseWriteAccess()
365 switch( m_eLockType
)
367 case E_NOTHING
: break; // There is nothing to do ...
369 m_pOwnMutex
->release();
372 case E_SOLARMUTEX
: {
373 m_pSolarMutex
->release();
376 case E_FAIRRWLOCK
: {
377 m_pFairRWLock
->releaseWriteAccess();
383 /*-************************************************************************************************************//**
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"!!!
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.
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.
406 *//*-*************************************************************************************************************/
407 void LockHelper::downgradeWriteAccess()
409 switch( m_eLockType
)
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();
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.
431 @return A reference to a static mutex/lock member.
433 @onerror No error should occure.
434 *//*-*************************************************************************************************************/
435 LockHelper
& LockHelper::getGlobalLock( ::vos::IMutex
* pSolarMutex
)
437 // Initialize static "member" only for one time!
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
;
449 ::osl::MutexGuard
aGuard( ::osl::Mutex::getGlobalMutex() );
452 static LockHelper
aLock( pSolarMutex
);
459 /*-************************************************************************************************************//**
460 @short return a reference to shared mutex member
461 @descr Sometimes we need a osl-mutex for sharing with our uno helper ...
463 a) If we have an initialized "own mutex" ... we can use it!
464 b) Otherwhise we must use a different mutex member :-(
470 @return A reference to a shared mutex.
472 @onerror No error should occure.
473 *//*-*************************************************************************************************************/
474 ::osl::Mutex
& LockHelper::getShareableOslMutex()
476 if( m_pShareableOslMutex
== NULL
)
478 ::osl::MutexGuard
aGuard( ::osl::Mutex::getGlobalMutex() );
479 if( m_pShareableOslMutex
== NULL
)
481 switch( m_eLockType
)
484 m_pShareableOslMutex
= m_pOwnMutex
;
488 m_pShareableOslMutex
= new ::osl::Mutex
;
494 return *m_pShareableOslMutex
;
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!
504 @attention We have numbered all our enum values for ELockType. So we can use it as value of searched
505 environment variable too!
507 @seealso enum ELockType
508 @seealso environment LOCKTYPE
511 @return A reference to a created and right initialized lock type!
513 @onerror We use a fallback!
514 *//*-*************************************************************************************************************/
515 ELockType
& LockHelper::implts_getLockType()
517 // Initialize static "member" only for one time!
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
;
529 ::osl::MutexGuard
aGuard( ::osl::Mutex::getGlobalMutex() );
532 static ELockType eType
= FALLBACK_LOCKTYPE
;
534 ::vos::OStartupInfo aEnvironment
;
535 ::rtl::OUString sValue
;
536 if( aEnvironment
.getEnvironment( ENVVAR_LOCKTYPE
, sValue
) == ::vos::OStartupInfo::E_None
)
538 eType
= (ELockType
)(sValue
.toInt32());
541 LOG_LOCKTYPE( FALLBACK_LOCKTYPE
, eType
)
549 } // namespace framework