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