LCOV - code coverage report
Current view: top level - libreoffice/framework/source/fwi/threadhelp - lockhelper.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 84 130 64.6 %
Date: 2012-12-27 Functions: 12 13 92.3 %
Legend: Lines: hit not hit

          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: */

Generated by: LCOV version 1.10