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

Generated by: LCOV version 1.10