LCOV - code coverage report
Current view: top level - chart2/source/tools - LifeTime.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 153 187 81.8 %
Date: 2015-06-13 12:38:46 Functions: 21 24 87.5 %
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 "LifeTime.hxx"
      21             : #include "macros.hxx"
      22             : #include <osl/diagnose.h>
      23             : 
      24             : #include <com/sun/star/util/XModifyListener.hpp>
      25             : #include <com/sun/star/util/XCloseListener.hpp>
      26             : 
      27             : using namespace ::com::sun::star;
      28             : 
      29             : namespace apphelper
      30             : {
      31             : 
      32         339 : LifeTimeManager::LifeTimeManager( lang::XComponent* pComponent, bool bLongLastingCallsCancelable )
      33             :     : m_aListenerContainer( m_aAccessMutex )
      34             :     , m_pComponent(pComponent)
      35         339 :     , m_bLongLastingCallsCancelable(bLongLastingCallsCancelable)
      36             : {
      37         339 :     impl_init();
      38         339 : }
      39             : 
      40         339 : void LifeTimeManager::impl_init()
      41             : {
      42         339 :     m_bDisposed = false;
      43         339 :     m_bInDispose = false;
      44         339 :     m_nAccessCount = 0;
      45         339 :     m_nLongLastingCallCount = 0;
      46         339 :     m_aNoAccessCountCondition.set();
      47         339 :     m_aNoLongLastingCallCountCondition.set();
      48         339 : }
      49             : 
      50         307 : LifeTimeManager::~LifeTimeManager()
      51             : {
      52         307 : }
      53             : 
      54       34677 : bool LifeTimeManager::impl_isDisposed( bool bAssert )
      55             : {
      56       34677 :     if( m_bDisposed || m_bInDispose )
      57             :     {
      58             :         if( bAssert )
      59             :         {
      60             :             OSL_FAIL( "This component is already disposed " );
      61             :             (void)(bAssert);
      62             :         }
      63           0 :         return true;
      64             :     }
      65       34677 :     return false;
      66             : }
      67             : 
      68           0 : bool LifeTimeManager::impl_canStartApiCall()
      69             : {
      70           0 :     if( impl_isDisposed() )
      71           0 :         return false; //behave passive if already disposed
      72             : 
      73             :     //mutex is acquired
      74           0 :     return true;
      75             : }
      76             : 
      77       29398 : void LifeTimeManager::impl_registerApiCall(bool bLongLastingCall)
      78             : {
      79             :     //only allowed if not disposed
      80             :     //do not acquire the mutex here because it will be acquired already
      81       29398 :     m_nAccessCount++;
      82       29398 :     if(m_nAccessCount==1)
      83             :         //@todo? is it ok to wake some threads here while we have acquired the mutex?
      84       28616 :         m_aNoAccessCountCondition.reset();
      85             : 
      86       29398 :     if(bLongLastingCall)
      87           0 :         m_nLongLastingCallCount++;
      88       29398 :     if(m_nLongLastingCallCount==1)
      89           0 :         m_aNoLongLastingCallCountCondition.reset();
      90       29398 : }
      91             : 
      92       29398 : void LifeTimeManager::impl_unregisterApiCall(bool bLongLastingCall)
      93             : {
      94             :     //Mutex needs to be acquired exactly ones
      95             :     //mutex may be released inbetween in special case of impl_apiCallCountReachedNull()
      96             : 
      97             :     OSL_ENSURE( m_nAccessCount>0, "access count mismatch" );
      98       29398 :     m_nAccessCount--;
      99       29398 :     if(bLongLastingCall)
     100           0 :         m_nLongLastingCallCount--;
     101       29398 :     if( m_nLongLastingCallCount==0 )
     102             :     {
     103       29398 :         m_aNoLongLastingCallCountCondition.set();
     104             :     }
     105       29398 :     if( m_nAccessCount== 0)
     106             :     {
     107       28616 :         m_aNoAccessCountCondition.set();
     108       28616 :         impl_apiCallCountReachedNull();
     109             : 
     110             :     }
     111       29398 : }
     112             : 
     113         677 : bool LifeTimeManager::dispose()
     114             :     throw(uno::RuntimeException)
     115             : {
     116             :     //hold no mutex
     117             :     {
     118         677 :         osl::Guard< osl::Mutex > aGuard( m_aAccessMutex );
     119             : 
     120         677 :         if( m_bDisposed || m_bInDispose )
     121             :         {
     122             :             OSL_TRACE( "This component is already disposed " );
     123         338 :             return false; //behave passive if already disposed
     124             :         }
     125             : 
     126         339 :         m_bInDispose = true;
     127             :         //adding any listener is not allowed anymore
     128             :         //new calls will not be accepted
     129             :         //still running calls have the freedom to finish their work without crash
     130             :     }
     131             :     //no mutex is acquired
     132             : 
     133             :     //--do the disposing of listeners after calling this method
     134             :     {
     135             :         uno::Reference< lang::XComponent > xComponent =
     136         339 :             uno::Reference< lang::XComponent >(m_pComponent);;
     137         339 :         if(xComponent.is())
     138             :         {
     139             :             // notify XCLoseListeners
     140         321 :             lang::EventObject aEvent( xComponent );
     141         321 :             m_aListenerContainer.disposeAndClear( aEvent );
     142         339 :         }
     143             :     }
     144             : 
     145             :     //no mutex is acquired
     146             :     {
     147         339 :         osl::ClearableGuard< osl::Mutex > aGuard( m_aAccessMutex );
     148             :         OSL_ENSURE( !m_bDisposed, "dispose was called already" );
     149         339 :         m_bDisposed = true;
     150         339 :         aGuard.clear();
     151             :     }
     152             :     //no mutex is acquired
     153             : 
     154             :     //wait until all still running calls have finished
     155             :     //the accessCount cannot grow anymore, because all calls will return after checking m_bDisposed
     156         339 :     m_aNoAccessCountCondition.wait();
     157             : 
     158             :     //we are the only ones working on our data now
     159             : 
     160         339 :     return true;
     161             :     //--release all resources and references after calling this method successful
     162             : }
     163             : 
     164         321 : CloseableLifeTimeManager::CloseableLifeTimeManager( ::com::sun::star::util::XCloseable* pCloseable
     165             :         , ::com::sun::star::lang::XComponent* pComponent
     166             :         , bool bLongLastingCallsCancelable )
     167             :         : LifeTimeManager( pComponent, bLongLastingCallsCancelable )
     168         321 :         , m_pCloseable(pCloseable)
     169             : {
     170         321 :     impl_init();
     171         321 : }
     172             : 
     173         305 : CloseableLifeTimeManager::~CloseableLifeTimeManager()
     174             : {
     175         305 : }
     176             : 
     177        4188 : bool CloseableLifeTimeManager::impl_isDisposedOrClosed( bool bAssert )
     178             : {
     179        4188 :     if( impl_isDisposed( bAssert ) )
     180           0 :         return true;
     181             : 
     182        4188 :     if( m_bClosed )
     183             :     {
     184             :         if( bAssert )
     185             :         {
     186             :             OSL_FAIL( "This object is already closed" );
     187             :             (void)(bAssert);//avoid warnings
     188             :         }
     189          15 :         return true;
     190             :     }
     191        4173 :     return false;
     192             : }
     193             : 
     194         320 : bool CloseableLifeTimeManager::g_close_startTryClose(bool bDeliverOwnership)
     195             :     throw ( uno::Exception )
     196             : {
     197             :     //no mutex is allowed to be acquired
     198             :     {
     199         320 :         osl::ResettableGuard< osl::Mutex > aGuard( m_aAccessMutex );
     200         320 :         if( impl_isDisposedOrClosed(false) )
     201           0 :             return false;
     202             : 
     203             :         //Mutex needs to be acquired exactly ones; will be released inbetween
     204         320 :         if( !impl_canStartApiCall() )
     205           0 :             return false;
     206             :         //mutex is acquired
     207             : 
     208             :         //not closed already -> we try to close again
     209         320 :         m_bInTryClose = true;
     210         320 :         m_aEndTryClosingCondition.reset();
     211             : 
     212         320 :         impl_registerApiCall(false);
     213             :     }
     214             : 
     215             :     //no mutex is acquired
     216             : 
     217             :     //only remove listener calls will be worked on until end of tryclose
     218             :     //all other new calls will wait till end of try close // @todo? is that really ok
     219             : 
     220             :     //?? still running calls have the freedom to finish their work without crash
     221             : 
     222             :     try
     223             :     {
     224             :         uno::Reference< util::XCloseable > xCloseable =
     225         320 :             uno::Reference< util::XCloseable >(m_pCloseable);;
     226         320 :         if(xCloseable.is())
     227             :         {
     228             :             //--call queryClosing on all registered close listeners
     229             :             ::cppu::OInterfaceContainerHelper* pIC = m_aListenerContainer.getContainer(
     230         320 :                         cppu::UnoType<util::XCloseListener>::get());;
     231         320 :             if( pIC )
     232             :             {
     233         320 :                 lang::EventObject aEvent( xCloseable );
     234         640 :                 ::cppu::OInterfaceIteratorHelper aIt( *pIC );
     235         959 :                 while( aIt.hasMoreElements() )
     236             :                 {
     237         320 :                     uno::Reference< util::XCloseListener > xCloseListener( aIt.next(), uno::UNO_QUERY );
     238         320 :                     if(xCloseListener.is())
     239         320 :                         xCloseListener->queryClosing( aEvent, bDeliverOwnership );
     240         640 :                 }
     241             :             }
     242         320 :         }
     243             :     }
     244           1 :     catch( const uno::Exception& )
     245             :     {
     246             :         //no mutex is acquired
     247           1 :         g_close_endTryClose(bDeliverOwnership, false);
     248           1 :         throw;
     249             :     }
     250         319 :     return true;
     251             : }
     252             : 
     253           1 : void CloseableLifeTimeManager::g_close_endTryClose(bool bDeliverOwnership, bool /* bMyVeto */ )
     254             : {
     255             :     //this method is called, if the try to close was not successful
     256           1 :     osl::Guard< osl::Mutex > aGuard( m_aAccessMutex );
     257           1 :     impl_setOwnership( bDeliverOwnership, false );
     258             : 
     259           1 :     m_bInTryClose = false;
     260           1 :     m_aEndTryClosingCondition.set();
     261             : 
     262             :     //Mutex needs to be acquired exactly ones
     263             :     //mutex may be released inbetween in special case of impl_apiCallCountReachedNull()
     264           1 :     impl_unregisterApiCall(false);
     265           1 : }
     266             : 
     267         319 : bool CloseableLifeTimeManager::g_close_isNeedToCancelLongLastingCalls( bool bDeliverOwnership, util::CloseVetoException& ex )
     268             :     throw ( util::CloseVetoException )
     269             : {
     270             :     //this method is called when no closelistener has had a veto during queryclosing
     271             :     //the method returns false, if nothing stands against closing anymore
     272             :     //it returns true, if some longlasting calls are running, which might be cancelled
     273             :     //it throws the given exception, if long calls are running but not cancelable
     274             : 
     275         319 :     osl::Guard< osl::Mutex > aGuard( m_aAccessMutex );
     276             :     //this count cannot grow after try of close has started, because we wait in all those methods for end of try closing
     277         319 :     if( !m_nLongLastingCallCount )
     278         319 :         return false;
     279             : 
     280           0 :       if(m_bLongLastingCallsCancelable)
     281           0 :         return true;
     282             : 
     283           0 :     impl_setOwnership( bDeliverOwnership, true );
     284             : 
     285           0 :     m_bInTryClose = false;
     286           0 :     m_aEndTryClosingCondition.set();
     287             : 
     288             :     //Mutex needs to be acquired exactly ones
     289             :     //mutex may be released inbetween in special case of impl_apiCallCountReachedNull()
     290           0 :     impl_unregisterApiCall(false);
     291             : 
     292           0 :     throw ex;
     293             : }
     294             : 
     295         319 : void CloseableLifeTimeManager::g_close_endTryClose_doClose()
     296             : {
     297             :     //this method is called, if the try to close was successful
     298         319 :     osl::ResettableGuard< osl::Mutex > aGuard( m_aAccessMutex );
     299             : 
     300         319 :     m_bInTryClose       = false;
     301         319 :     m_aEndTryClosingCondition.set();
     302             : 
     303             :     //Mutex needs to be acquired exactly ones
     304             :     //mutex may be released inbetween in special case of impl_apiCallCountReachedNull()
     305         319 :     impl_unregisterApiCall(false);
     306         319 :     impl_doClose();
     307         319 : }
     308             : 
     309           1 : void CloseableLifeTimeManager::impl_setOwnership( bool bDeliverOwnership, bool bMyVeto )
     310             : {
     311           1 :     m_bOwnership            = bDeliverOwnership && bMyVeto;
     312           1 : }
     313             : 
     314       28616 : void CloseableLifeTimeManager::impl_apiCallCountReachedNull()
     315             : {
     316             :     //Mutex needs to be acquired exactly ones
     317             :     //mutex will be released inbetween in impl_doClose()
     318       28616 :     if( m_pCloseable && impl_shouldCloseAtNextChance() )
     319           0 :         impl_doClose();
     320       28616 : }
     321             : 
     322         319 : void CloseableLifeTimeManager::impl_doClose()
     323             : {
     324             :     //Mutex needs to be acquired exactly ones before calling impl_doClose()
     325             : 
     326         319 :     if(m_bClosed)
     327           0 :         return; //behave as passive as possible, if disposed or closed already
     328         319 :     if( m_bDisposed || m_bInDispose )
     329           0 :         return; //behave as passive as possible, if disposed or closed already
     330             : 
     331         319 :     m_bClosed = true;
     332             : 
     333         319 :     NegativeGuard< osl::Mutex > aNegativeGuard( m_aAccessMutex );
     334             :     //mutex is not acquired, mutex will be reacquired at the end of this method automatically
     335             : 
     336         638 :     uno::Reference< util::XCloseable > xCloseable=NULL;
     337             :     try
     338             :     {
     339         319 :         xCloseable = uno::Reference< util::XCloseable >(m_pCloseable);;
     340         319 :         if(xCloseable.is())
     341             :         {
     342             :             //--call notifyClosing on all registered close listeners
     343             :             ::cppu::OInterfaceContainerHelper* pIC = m_aListenerContainer.getContainer(
     344         319 :                         cppu::UnoType<util::XCloseListener>::get());;
     345         319 :             if( pIC )
     346             :             {
     347         319 :                 lang::EventObject aEvent( xCloseable );
     348         638 :                 ::cppu::OInterfaceIteratorHelper aIt( *pIC );
     349         957 :                 while( aIt.hasMoreElements() )
     350             :                 {
     351         319 :                     uno::Reference< util::XCloseListener > xListener( aIt.next(), uno::UNO_QUERY );
     352         319 :                     if( xListener.is() )
     353         319 :                         xListener->notifyClosing( aEvent );
     354         638 :                 }
     355             :             }
     356             :         }
     357             :     }
     358           0 :     catch( const uno::Exception& ex )
     359             :     {
     360             :         ASSERT_EXCEPTION( ex );
     361             :     }
     362             : 
     363         319 :     if(xCloseable.is())
     364             :     {
     365             :         uno::Reference< lang::XComponent > xComponent =
     366         319 :             uno::Reference< lang::XComponent >( xCloseable, uno::UNO_QUERY );
     367         319 :         if(xComponent.is())
     368             :         {
     369             :             OSL_ENSURE( m_bClosed, "a not closed component will be disposed " );
     370         319 :             xComponent->dispose();
     371         319 :         }
     372         319 :     }
     373             :     //mutex will be reacquired in destructor of aNegativeGuard
     374             : }
     375             : 
     376         321 : bool CloseableLifeTimeManager::g_addCloseListener( const uno::Reference< util::XCloseListener > & xListener )
     377             :     throw(uno::RuntimeException)
     378             : {
     379         321 :     osl::Guard< osl::Mutex > aGuard( m_aAccessMutex );
     380             :     //Mutex needs to be acquired exactly ones; will be released inbetween
     381         321 :     if( !impl_canStartApiCall() )
     382           0 :         return false;
     383             :     //mutex is acquired
     384             : 
     385         321 :     m_aListenerContainer.addInterface( cppu::UnoType<util::XCloseListener>::get(),xListener );
     386         321 :     m_bOwnership = false;
     387         321 :     return true;
     388             : }
     389             : 
     390       29719 : bool CloseableLifeTimeManager::impl_canStartApiCall()
     391             : {
     392             :     //Mutex needs to be acquired exactly ones before calling this method
     393             :     //the mutex will be released inbetween and reacquired
     394             : 
     395       29719 :     if( impl_isDisposed() )
     396           0 :         return false; //behave passive if already disposed
     397       29719 :     if( m_bClosed )
     398           0 :         return false; //behave passive if closing is already done
     399             : 
     400             :     //during try-close most calls need to wait for the decision
     401       59438 :     while( m_bInTryClose )
     402             :     {
     403             :         //if someone tries to close this object at the moment
     404             :         //we need to wait for his end because the result of the preceding call
     405             :         //is relevant for our behaviour here
     406             : 
     407           0 :         m_aAccessMutex.release();
     408           0 :         m_aEndTryClosingCondition.wait(); //@todo??? this may block??? try closing
     409           0 :         m_aAccessMutex.acquire();
     410           0 :         if( m_bDisposed || m_bInDispose || m_bClosed )
     411           0 :             return false; //return if closed already
     412             :     }
     413             :     //mutex is acquired
     414       29719 :     return true;
     415             : }
     416             : 
     417       29078 : bool LifeTimeGuard::startApiCall(bool bLongLastingCall)
     418             : {
     419             :     //Mutex needs to be acquired exactly ones; will be released inbetween
     420             :     //mutex is requiered due to constructor of LifeTimeGuard
     421             : 
     422             :     OSL_ENSURE( !m_bCallRegistered, "this method is only allowed ones" );
     423       29078 :     if(m_bCallRegistered)
     424           0 :         return false;
     425             : 
     426             :     //Mutex needs to be acquired exactly ones; will be released inbetween
     427       29078 :     if( !m_rManager.impl_canStartApiCall() )
     428           0 :         return false;
     429             :     //mutex is acquired
     430             : 
     431       29078 :     m_bCallRegistered = true;
     432       29078 :     m_bLongLastingCallRegistered = bLongLastingCall;
     433       29078 :     m_rManager.impl_registerApiCall(bLongLastingCall);
     434       29078 :     return true;
     435             : }
     436             : 
     437       58156 : LifeTimeGuard::~LifeTimeGuard()
     438             : {
     439             :     try
     440             :     {
     441             :         //do acquire the mutex if it was cleared before
     442       29078 :         osl::MutexGuard g(m_rManager.m_aAccessMutex);
     443       29078 :         if(m_bCallRegistered)
     444             :         {
     445             :             //Mutex needs to be acquired exactly ones
     446             :             //mutex may be released inbetween in special case of impl_apiCallCountReachedNull()
     447       29078 :             m_rManager.impl_unregisterApiCall(m_bLongLastingCallRegistered);
     448       29078 :         }
     449             :     }
     450           0 :     catch( uno::Exception& ex )
     451             :     {
     452             :         //@todo ? allow a uno::RuntimeException from dispose to travel through??
     453           0 :         ex.Context.is(); //to avoid compilation warnings
     454             :     }
     455       29078 : }
     456             : 
     457             : }//end namespace apphelper
     458             : 
     459             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11