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