LCOV - code coverage report
Current view: top level - sw/source/core/docnode - finalthreadmanager.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 33 185 17.8 %
Date: 2015-06-13 12:38:46 Functions: 9 33 27.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 <finalthreadmanager.hxx>
      21             : 
      22             : #include <osl/diagnose.h>
      23             : #include <osl/thread.hxx>
      24             : #include <pausethreadstarting.hxx>
      25             : #include <swthreadjoiner.hxx>
      26             : 
      27             : #include <com/sun/star/frame/Desktop.hpp>
      28             : #include <rtl/ustring.hxx>
      29             : #include <com/sun/star/frame/XFramesSupplier.hpp>
      30             : #include <cppuhelper/supportsservice.hxx>
      31             : 
      32             : /** thread to cancel a give list of cancellable jobs
      33             : 
      34             :     helper class for FinalThreadManager
      35             : */
      36             : class CancelJobsThread : public osl::Thread
      37             : {
      38             :     public:
      39           0 :         explicit CancelJobsThread( std::list< css::uno::Reference< css::util::XCancellable > > aJobs )
      40             :             : osl::Thread(),
      41             :               maMutex(),
      42             :               maJobs( aJobs ),
      43             :               mbAllJobsCancelled( false ),
      44           0 :               mbStopped( false )
      45             :         {
      46           0 :         }
      47             : 
      48           0 :         virtual ~CancelJobsThread() {}
      49             : 
      50             :         void addJobs( std::list< css::uno::Reference< css::util::XCancellable > >& rJobs );
      51             :         bool allJobsCancelled() const;
      52             :         void stopWhenAllJobsCancelled();
      53             : 
      54             :     private:
      55             :         bool existJobs() const;
      56             : 
      57             :         css::uno::Reference< css::util::XCancellable > getNextJob();
      58             : 
      59             :         bool stopped() const;
      60             :         virtual void SAL_CALL run() SAL_OVERRIDE;
      61             :         mutable osl::Mutex maMutex;
      62             : 
      63             :         std::list< css::uno::Reference< css::util::XCancellable > > maJobs;
      64             : 
      65             :         bool mbAllJobsCancelled;
      66             :         bool mbStopped;
      67             : };
      68             : 
      69           0 : void CancelJobsThread::addJobs( std::list< css::uno::Reference< css::util::XCancellable > >& rJobs )
      70             : {
      71           0 :     osl::MutexGuard aGuard(maMutex);
      72             : 
      73           0 :     maJobs.insert( maJobs.end(), rJobs.begin(), rJobs.end() );
      74           0 :     mbAllJobsCancelled = !maJobs.empty();
      75           0 : }
      76             : 
      77           0 : bool CancelJobsThread::existJobs() const
      78             : {
      79           0 :     osl::MutexGuard aGuard(maMutex);
      80             : 
      81           0 :     return !maJobs.empty();
      82             : }
      83             : 
      84           0 : bool CancelJobsThread::allJobsCancelled() const
      85             : {
      86           0 :     osl::MutexGuard aGuard(maMutex);
      87             : 
      88           0 :     return maJobs.empty() && mbAllJobsCancelled;
      89             : }
      90             : 
      91           0 : void CancelJobsThread::stopWhenAllJobsCancelled()
      92             : {
      93           0 :     osl::MutexGuard aGuard(maMutex);
      94             : 
      95           0 :     mbStopped = true;
      96           0 : }
      97             : 
      98           0 : css::uno::Reference< css::util::XCancellable > CancelJobsThread::getNextJob()
      99             : {
     100           0 :     css::uno::Reference< css::util::XCancellable > xRet;
     101             : 
     102             :     {
     103           0 :         osl::MutexGuard aGuard(maMutex);
     104             : 
     105           0 :         if ( !maJobs.empty() )
     106             :         {
     107           0 :             xRet = maJobs.front();
     108           0 :             maJobs.pop_front();
     109           0 :         }
     110             :     }
     111             : 
     112           0 :     return xRet;
     113             : }
     114             : 
     115           0 : bool CancelJobsThread::stopped() const
     116             : {
     117           0 :     osl::MutexGuard aGuard(maMutex);
     118             : 
     119           0 :     return mbStopped;
     120             : }
     121             : 
     122           0 : void SAL_CALL CancelJobsThread::run()
     123             : {
     124           0 :     osl_setThreadName("sw CancelJobsThread");
     125             : 
     126           0 :     while ( !stopped() )
     127             :     {
     128           0 :         while ( existJobs() )
     129             :         {
     130           0 :             css::uno::Reference< css::util::XCancellable > aJob( getNextJob() );
     131           0 :             if ( aJob.is() )
     132           0 :                 aJob->cancel();
     133           0 :         }
     134             : 
     135           0 :         mbAllJobsCancelled = true;
     136             : 
     137             :         {
     138             :             TimeValue aSleepTime;
     139           0 :             aSleepTime.Seconds = 1;
     140           0 :             aSleepTime.Nanosec = 0;
     141           0 :             osl_waitThread( &aSleepTime );
     142             :         }
     143             :     }
     144           0 : }
     145             : 
     146             : /** thread to terminate office, when all jobs are cancelled.
     147             : 
     148             :     helper class for FinalThreadManager
     149             : */
     150             : class TerminateOfficeThread : public osl::Thread
     151             : {
     152             :     public:
     153           0 :         TerminateOfficeThread( CancelJobsThread& rCancelJobsThread,
     154             :                                css::uno::Reference< css::uno::XComponentContext > const & xContext )
     155             :             : osl::Thread(),
     156             :               maMutex(),
     157             :               mrCancelJobsThread( rCancelJobsThread ),
     158             :               mbStopOfficeTermination( false ),
     159           0 :               mxContext( xContext )
     160             :         {
     161           0 :         }
     162             : 
     163           0 :         virtual ~TerminateOfficeThread() {}
     164             :         void StopOfficeTermination();
     165             : 
     166             :     private:
     167             :         virtual void SAL_CALL run() SAL_OVERRIDE;
     168             :         virtual void SAL_CALL onTerminated() SAL_OVERRIDE;
     169             :         bool OfficeTerminationStopped();
     170             :         void PerformOfficeTermination();
     171             : 
     172             :         osl::Mutex maMutex;
     173             : 
     174             :         const CancelJobsThread& mrCancelJobsThread;
     175             :         bool mbStopOfficeTermination;
     176             : 
     177             :         css::uno::Reference< css::uno::XComponentContext > mxContext;
     178             : };
     179             : 
     180           0 : void TerminateOfficeThread::StopOfficeTermination()
     181             : {
     182           0 :     osl::MutexGuard aGuard(maMutex);
     183             : 
     184           0 :     mbStopOfficeTermination = true;
     185           0 : }
     186             : 
     187           0 : bool TerminateOfficeThread::OfficeTerminationStopped()
     188             : {
     189           0 :     osl::MutexGuard aGuard(maMutex);
     190             : 
     191           0 :     return mbStopOfficeTermination;
     192             : }
     193             : 
     194           0 : void SAL_CALL TerminateOfficeThread::run()
     195             : {
     196           0 :     osl_setThreadName("sw TerminateOfficeThread");
     197             : 
     198           0 :     while ( !OfficeTerminationStopped() )
     199             :     {
     200           0 :         osl::MutexGuard aGuard(maMutex);
     201             : 
     202           0 :         if ( mrCancelJobsThread.allJobsCancelled() )
     203           0 :             break;
     204           0 :     }
     205             : 
     206           0 :     if ( !OfficeTerminationStopped() )
     207           0 :         PerformOfficeTermination();
     208           0 : }
     209             : 
     210           0 : void TerminateOfficeThread::PerformOfficeTermination()
     211             : {
     212           0 :     css::uno::Reference< css::frame::XDesktop2 > xDesktop = css::frame::Desktop::create(mxContext);
     213             : 
     214           0 :     css::uno::Reference< css::container::XElementAccess > xList( xDesktop->getFrames(), css::uno::UNO_QUERY );
     215           0 :     if ( !xList.is() )
     216             :     {
     217             :         OSL_FAIL( "<TerminateOfficeThread::PerformOfficeTermination()> - no XElementAccess!" );
     218           0 :         return;
     219             :     }
     220             : 
     221           0 :     if ( !xList->hasElements() )
     222             :     {
     223           0 :         if ( !OfficeTerminationStopped() )
     224           0 :             xDesktop->terminate();
     225           0 :     }
     226             : }
     227             : 
     228           0 : void SAL_CALL TerminateOfficeThread::onTerminated()
     229             : {
     230           0 :     if ( OfficeTerminationStopped() )
     231           0 :         delete this;
     232           0 : }
     233             : 
     234           2 : FinalThreadManager::FinalThreadManager(css::uno::Reference< css::uno::XComponentContext > const & context)
     235             :     : m_xContext(context),
     236             :       maMutex(),
     237             :       maThreads(),
     238             :       mpCancelJobsThread( 0 ),
     239             :       mpTerminateOfficeThread( 0 ),
     240             :       mpPauseThreadStarting( 0 ),
     241           2 :       mbRegisteredAtDesktop( false )
     242             : {
     243             : 
     244           2 : }
     245             : 
     246           1 : void FinalThreadManager::registerAsListenerAtDesktop()
     247             : {
     248           1 :     css::uno::Reference< css::frame::XDesktop2 > xDesktop = css::frame::Desktop::create(m_xContext);
     249           1 :     xDesktop->addTerminateListener( css::uno::Reference< css::frame::XTerminateListener >( static_cast< cppu::OWeakObject* >( this ), css::uno::UNO_QUERY ) );
     250           1 : }
     251             : 
     252           6 : FinalThreadManager::~FinalThreadManager()
     253             : {
     254           2 :     if ( mpPauseThreadStarting != 0 )
     255             :     {
     256           0 :         delete mpPauseThreadStarting;
     257           0 :         mpPauseThreadStarting = 0;
     258             :     }
     259             : 
     260           2 :     if ( mpTerminateOfficeThread != 0 )
     261             :     {
     262           0 :         mpTerminateOfficeThread->StopOfficeTermination(); // thread kills itself.
     263           0 :         mpTerminateOfficeThread = 0;
     264             :     }
     265             : 
     266           2 :     if ( !maThreads.empty() )
     267             :     {
     268             :         OSL_FAIL( "<FinalThreadManager::~FinalThreadManager()> - still registered jobs are existing -> perform cancellation" );
     269           0 :         cancelAllJobs();
     270             :     }
     271             : 
     272           2 :     if ( mpCancelJobsThread != 0 )
     273             :     {
     274           0 :         if ( !mpCancelJobsThread->allJobsCancelled() )
     275             :             OSL_FAIL( "<FinalThreadManager::~FinalThreadManager()> - cancellation of registered jobs not yet finished -> wait for its finish" );
     276             : 
     277           0 :         mpCancelJobsThread->stopWhenAllJobsCancelled();
     278           0 :         mpCancelJobsThread->join();
     279           0 :         delete mpCancelJobsThread;
     280           0 :         mpCancelJobsThread = 0;
     281             :     }
     282           4 : }
     283             : 
     284             : // com.sun.star.uno.XServiceInfo:
     285           2 : OUString SAL_CALL FinalThreadManager::getImplementationName() throw (css::uno::RuntimeException, std::exception)
     286             : {
     287           2 :     return OUString("com.sun.star.util.comp.FinalThreadManager");
     288             : }
     289             : 
     290           0 : sal_Bool SAL_CALL FinalThreadManager::supportsService(OUString const & serviceName) throw (css::uno::RuntimeException, std::exception)
     291             : {
     292           0 :     return cppu::supportsService(this, serviceName);
     293             : }
     294             : 
     295           1 : css::uno::Sequence< OUString > SAL_CALL FinalThreadManager::getSupportedServiceNames() throw (css::uno::RuntimeException, std::exception)
     296             : {
     297           1 :     css::uno::Sequence< OUString > s(1);
     298           1 :     s[0] = "com.sun.star.util.JobManager";
     299           1 :     return s;
     300             : }
     301             : 
     302             : // ::com::sun::star::util::XJobManager:
     303           4 : void SAL_CALL FinalThreadManager::registerJob(const css::uno::Reference< css::util::XCancellable > & Job) throw (css::uno::RuntimeException, std::exception)
     304             : {
     305           4 :     osl::MutexGuard aGuard(maMutex);
     306             : 
     307           4 :     maThreads.push_back( Job );
     308             : 
     309           4 :     if ( !mbRegisteredAtDesktop )
     310             :     {
     311           1 :         registerAsListenerAtDesktop();
     312           1 :         mbRegisteredAtDesktop = true;
     313           4 :     }
     314           4 : }
     315             : 
     316           4 : void SAL_CALL FinalThreadManager::releaseJob(const css::uno::Reference< css::util::XCancellable > & Job) throw (css::uno::RuntimeException, std::exception)
     317             : {
     318           4 :     osl::MutexGuard aGuard(maMutex);
     319             : 
     320           4 :     maThreads.remove( Job );
     321           4 : }
     322             : 
     323           0 : void SAL_CALL FinalThreadManager::cancelAllJobs() throw (css::uno::RuntimeException, std::exception)
     324             : {
     325           0 :     std::list< css::uno::Reference< css::util::XCancellable > > aThreads;
     326             :     {
     327           0 :         osl::MutexGuard aGuard(maMutex);
     328             : 
     329           0 :         aThreads.insert( aThreads.end(), maThreads.begin(), maThreads.end() );
     330           0 :         maThreads.clear();
     331             :     }
     332             : 
     333           0 :     if ( !aThreads.empty() )
     334             :     {
     335           0 :         osl::MutexGuard aGuard(maMutex);
     336             : 
     337           0 :         if ( mpCancelJobsThread == 0 )
     338             :         {
     339           0 :             mpCancelJobsThread = new CancelJobsThread( aThreads );;
     340           0 :             if ( !mpCancelJobsThread->create() )
     341             :             {
     342           0 :                 delete mpCancelJobsThread;
     343           0 :                 mpCancelJobsThread = 0;
     344           0 :                 while ( !aThreads.empty() )
     345             :                 {
     346           0 :                     aThreads.front()->cancel();
     347           0 :                     aThreads.pop_front();
     348             :                 }
     349             :             }
     350             :         }
     351             :         else
     352           0 :             mpCancelJobsThread->addJobs( aThreads );
     353           0 :     }
     354           0 : }
     355             : 
     356             : // ::com::sun::star::frame::XTerminateListener
     357           0 : void SAL_CALL FinalThreadManager::queryTermination( const css::lang::EventObject& ) throw (css::frame::TerminationVetoException, css::uno::RuntimeException, std::exception)
     358             : {
     359           0 :     osl::MutexGuard aGuard(maMutex);
     360             : 
     361           0 :     cancelAllJobs();
     362             :     // Sleep 1 second to give the thread for job cancellation some time.
     363             :     // Probably, all started threads have already finished its work.
     364           0 :     if ( mpCancelJobsThread != 0 &&
     365           0 :          !mpCancelJobsThread->allJobsCancelled() )
     366             :     {
     367             :         TimeValue aSleepTime;
     368           0 :         aSleepTime.Seconds = 1;
     369           0 :         aSleepTime.Nanosec = 0;
     370           0 :         osl_waitThread( &aSleepTime );
     371             :     }
     372             : 
     373           0 :     if ( mpCancelJobsThread != 0 &&
     374           0 :          !mpCancelJobsThread->allJobsCancelled() )
     375             :     {
     376           0 :         if ( mpTerminateOfficeThread != 0 )
     377             :         {
     378           0 :             if ( mpTerminateOfficeThread->isRunning() )
     379           0 :                 mpTerminateOfficeThread->StopOfficeTermination(); // thread kills itself.
     380             :             else
     381           0 :                 delete mpTerminateOfficeThread;
     382             : 
     383           0 :             mpTerminateOfficeThread = 0;
     384             :         }
     385             :         mpTerminateOfficeThread = new TerminateOfficeThread( *mpCancelJobsThread,
     386           0 :                                                  m_xContext );
     387           0 :         if ( !mpTerminateOfficeThread->create() )
     388             :         {
     389           0 :             delete mpTerminateOfficeThread;
     390           0 :             mpTerminateOfficeThread = 0;
     391             :         }
     392             : 
     393           0 :         throw css::frame::TerminationVetoException();
     394             :     }
     395             : 
     396           0 :     mpPauseThreadStarting = new SwPauseThreadStarting();
     397             : 
     398           0 :     return;
     399             : }
     400             : 
     401           0 : void SAL_CALL FinalThreadManager::cancelTermination( const css::lang::EventObject& ) throw (css::uno::RuntimeException, std::exception)
     402             : {
     403           0 :     if ( mpPauseThreadStarting != 0 )
     404             :     {
     405           0 :         delete mpPauseThreadStarting;
     406           0 :         mpPauseThreadStarting = 0;
     407             :     }
     408             : 
     409           0 :     return;
     410             : }
     411             : 
     412           0 : void SAL_CALL FinalThreadManager::notifyTermination( const css::lang::EventObject& ) throw (css::uno::RuntimeException, std::exception)
     413             : {
     414           0 :     if ( mpTerminateOfficeThread != 0 )
     415             :     {
     416           0 :         if ( mpTerminateOfficeThread->isRunning() )
     417           0 :             mpTerminateOfficeThread->StopOfficeTermination(); // thread kills itself.
     418             :         else
     419           0 :             delete mpTerminateOfficeThread;
     420             : 
     421           0 :         mpTerminateOfficeThread = 0;
     422             :     }
     423             : 
     424           0 :     if ( !maThreads.empty() )
     425           0 :         cancelAllJobs();
     426             : 
     427           0 :     if ( mpCancelJobsThread != 0 )
     428             :     {
     429           0 :         mpCancelJobsThread->stopWhenAllJobsCancelled();
     430           0 :         mpCancelJobsThread->join();
     431           0 :         delete mpCancelJobsThread;
     432           0 :         mpCancelJobsThread = 0;
     433             :     }
     434             : 
     435             :     // get reference of this
     436           0 :     css::uno::Reference< css::uno::XInterface > aOwnRef( static_cast< cppu::OWeakObject* >( this ));
     437             :     // notify <SwThreadJoiner> to release its reference
     438           0 :     SwThreadJoiner::ReleaseThreadJoiner();
     439           0 : }
     440             : 
     441             : // ::com::sun:star::lang::XEventListener (inherited via com::sun::star::frame::XTerminateListener)
     442           0 : void SAL_CALL FinalThreadManager::disposing( const css::lang::EventObject& ) throw (css::uno::RuntimeException, std::exception)
     443             : {
     444             :     // nothing to do, because instance doesn't hold any references of observed objects
     445           0 : }
     446             : 
     447             : extern "C" SAL_DLLPUBLIC_EXPORT ::com::sun::star::uno::XInterface* SAL_CALL
     448           2 : com_sun_star_util_comp_FinalThreadManager_get_implementation(::com::sun::star::uno::XComponentContext* context,
     449             :                                 ::com::sun::star::uno::Sequence<css::uno::Any> const &)
     450             : {
     451           2 :     return cppu::acquire(new FinalThreadManager(context));
     452             : }
     453             : 
     454             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11