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