1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: finalthreadmanager.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
30 #include "precompiled_sw.hxx"
31 #include <finalthreadmanager.hxx>
33 #ifndef _OSL_THREAD_HXX_
34 #include <osl/thread.hxx>
37 #include <pausethreadstarting.hxx>
38 #include <swthreadjoiner.hxx>
40 #include <com/sun/star/frame/XDesktop.hpp>
41 #include <rtl/ustring.hxx>
42 #include <com/sun/star/frame/XFramesSupplier.hpp>
44 namespace css
= ::com::sun::star
;
46 /** thread to cancel a give list of cancellable jobs
48 helper class for FinalThreadManager
52 class CancelJobsThread
: public osl::Thread
55 CancelJobsThread( std::list
< css::uno::Reference
< css::util::XCancellable
> > aJobs
)
59 mbAllJobsCancelled( false ),
64 virtual ~CancelJobsThread() {}
66 void addJobs( std::list
< css::uno::Reference
< css::util::XCancellable
> >& rJobs
);
68 bool allJobsCancelled() const;
70 void stopWhenAllJobsCancelled();
74 bool existJobs() const;
76 css::uno::Reference
< css::util::XCancellable
> getNextJob();
80 virtual void SAL_CALL
run();
82 mutable osl::Mutex maMutex
;
84 std::list
< css::uno::Reference
< css::util::XCancellable
> > maJobs
;
86 bool mbAllJobsCancelled
;
90 void CancelJobsThread::addJobs( std::list
< css::uno::Reference
< css::util::XCancellable
> >& rJobs
)
92 osl::MutexGuard
aGuard(maMutex
);
94 maJobs
.insert( maJobs
.end(), rJobs
.begin(), rJobs
.end() );
95 mbAllJobsCancelled
= !maJobs
.empty();
98 bool CancelJobsThread::existJobs() const
100 osl::MutexGuard
aGuard(maMutex
);
102 return !maJobs
.empty();
105 bool CancelJobsThread::allJobsCancelled() const
107 osl::MutexGuard
aGuard(maMutex
);
109 return maJobs
.empty() && mbAllJobsCancelled
;
111 void CancelJobsThread::stopWhenAllJobsCancelled()
113 osl::MutexGuard
aGuard(maMutex
);
118 css::uno::Reference
< css::util::XCancellable
> CancelJobsThread::getNextJob()
120 css::uno::Reference
< css::util::XCancellable
> xRet
;
123 osl::MutexGuard
aGuard(maMutex
);
125 if ( !maJobs
.empty() )
127 xRet
= maJobs
.front();
135 bool CancelJobsThread::stopped() const
137 osl::MutexGuard
aGuard(maMutex
);
142 void SAL_CALL
CancelJobsThread::run()
146 while ( existJobs() )
148 css::uno::Reference
< css::util::XCancellable
> aJob( getNextJob() );
155 mbAllJobsCancelled
= true;
158 TimeValue aSleepTime
;
159 aSleepTime
.Seconds
= 1;
160 aSleepTime
.Nanosec
= 0;
161 osl_waitThread( &aSleepTime
);
166 /** thread to terminate office, when all jobs are cancelled.
168 helper class for FinalThreadManager
172 class TerminateOfficeThread
: public osl::Thread
175 TerminateOfficeThread( CancelJobsThread
& rCancelJobsThread
,
176 css::uno::Reference
< css::uno::XComponentContext
> const & xContext
)
179 mrCancelJobsThread( rCancelJobsThread
),
180 mbStopOfficeTermination( false ),
181 mxContext( xContext
)
185 virtual ~TerminateOfficeThread() {}
187 void StopOfficeTermination();
191 virtual void SAL_CALL
run();
192 virtual void SAL_CALL
onTerminated();
194 bool OfficeTerminationStopped();
196 void PerformOfficeTermination();
200 const CancelJobsThread
& mrCancelJobsThread
;
202 bool mbStopOfficeTermination
;
204 css::uno::Reference
< css::uno::XComponentContext
> mxContext
;
207 void TerminateOfficeThread::StopOfficeTermination()
209 osl::MutexGuard
aGuard(maMutex
);
211 mbStopOfficeTermination
= true;
214 bool TerminateOfficeThread::OfficeTerminationStopped()
216 osl::MutexGuard
aGuard(maMutex
);
218 return mbStopOfficeTermination
;
221 void SAL_CALL
TerminateOfficeThread::run()
223 while ( !OfficeTerminationStopped() )
225 osl::MutexGuard
aGuard(maMutex
);
227 if ( mrCancelJobsThread
.allJobsCancelled() )
233 if ( !OfficeTerminationStopped() )
235 PerformOfficeTermination();
239 void TerminateOfficeThread::PerformOfficeTermination()
241 css::uno::Reference
< css::frame::XFramesSupplier
> xTasksSupplier(
242 mxContext
->getServiceManager()->createInstanceWithContext(
243 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.frame.Desktop") ),
245 css::uno::UNO_QUERY
);
246 if ( !xTasksSupplier
.is() )
248 ASSERT( false, "<TerminateOfficeThread::PerformOfficeTermination()> - no XFramesSupplier!" );
252 css::uno::Reference
< css::container::XElementAccess
> xList( xTasksSupplier
->getFrames(), css::uno::UNO_QUERY
);
255 ASSERT( false, "<TerminateOfficeThread::PerformOfficeTermination()> - no XElementAccess!" );
259 if ( !xList
->hasElements() )
261 css::uno::Reference
< css::frame::XDesktop
> xDesktop( xTasksSupplier
, css::uno::UNO_QUERY
);
262 if ( xDesktop
.is() && !OfficeTerminationStopped() )
264 xDesktop
->terminate();
269 void SAL_CALL
TerminateOfficeThread::onTerminated()
271 if ( OfficeTerminationStopped() )
278 /** class FinalThreadManager
282 FinalThreadManager::FinalThreadManager(css::uno::Reference
< css::uno::XComponentContext
> const & context
)
283 : m_xContext(context
),
286 mpCancelJobsThread( 0 ),
287 mpTerminateOfficeThread( 0 ),
288 mpPauseThreadStarting( 0 ),
289 mbRegisteredAtDesktop( false )
294 void FinalThreadManager::registerAsListenerAtDesktop()
296 css::uno::Reference
< css::frame::XDesktop
> xDesktop(
297 m_xContext
->getServiceManager()->createInstanceWithContext(
298 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.frame.Desktop") ),
300 css::uno::UNO_QUERY
);
304 xDesktop
->addTerminateListener( css::uno::Reference
< css::frame::XTerminateListener
>( static_cast< cppu::OWeakObject
* >( this ), css::uno::UNO_QUERY
) );
308 FinalThreadManager::~FinalThreadManager()
310 if ( mpPauseThreadStarting
!= 0 )
312 delete mpPauseThreadStarting
;
313 mpPauseThreadStarting
= 0;
316 if ( mpTerminateOfficeThread
!= 0 )
318 mpTerminateOfficeThread
->StopOfficeTermination(); // thread kills itself.
319 mpTerminateOfficeThread
= 0;
322 if ( !maThreads
.empty() )
324 ASSERT( false, "<FinalThreadManager::~FinalThreadManager()> - still registered jobs are existing -> perform cancellation" );
328 if ( mpCancelJobsThread
!= 0 )
330 if ( !mpCancelJobsThread
->allJobsCancelled() )
332 ASSERT( false, "<FinalThreadManager::~FinalThreadManager()> - cancellation of registered jobs not yet finished -> wait for its finish" );
335 mpCancelJobsThread
->stopWhenAllJobsCancelled();
336 mpCancelJobsThread
->join();
337 delete mpCancelJobsThread
;
338 mpCancelJobsThread
= 0;
342 // com.sun.star.uno.XServiceInfo:
343 ::rtl::OUString SAL_CALL
FinalThreadManager::getImplementationName() throw (css::uno::RuntimeException
)
345 return comp_FinalThreadManager::_getImplementationName();
348 ::sal_Bool SAL_CALL
FinalThreadManager::supportsService(::rtl::OUString
const & serviceName
) throw (css::uno::RuntimeException
)
350 css::uno::Sequence
< ::rtl::OUString
> serviceNames
= comp_FinalThreadManager::_getSupportedServiceNames();
351 for (::sal_Int32 i
= 0; i
< serviceNames
.getLength(); ++i
) {
352 if (serviceNames
[i
] == serviceName
)
358 css::uno::Sequence
< ::rtl::OUString
> SAL_CALL
FinalThreadManager::getSupportedServiceNames() throw (css::uno::RuntimeException
)
360 return comp_FinalThreadManager::_getSupportedServiceNames();
363 // ::com::sun::star::util::XJobManager:
364 void SAL_CALL
FinalThreadManager::registerJob(const css::uno::Reference
< css::util::XCancellable
> & Job
) throw (css::uno::RuntimeException
)
366 osl::MutexGuard
aGuard(maMutex
);
368 maThreads
.push_back( Job
);
370 if ( !mbRegisteredAtDesktop
)
372 registerAsListenerAtDesktop();
373 mbRegisteredAtDesktop
= true;
377 void SAL_CALL
FinalThreadManager::releaseJob(const css::uno::Reference
< css::util::XCancellable
> & Job
) throw (css::uno::RuntimeException
)
379 osl::MutexGuard
aGuard(maMutex
);
381 maThreads
.remove( Job
);
384 void SAL_CALL
FinalThreadManager::cancelAllJobs() throw (css::uno::RuntimeException
)
386 std::list
< css::uno::Reference
< css::util::XCancellable
> > aThreads
;
388 osl::MutexGuard
aGuard(maMutex
);
390 aThreads
.insert( aThreads
.end(), maThreads
.begin(), maThreads
.end() );
394 if ( !aThreads
.empty() )
396 osl::MutexGuard
aGuard(maMutex
);
398 if ( mpCancelJobsThread
== 0 )
400 mpCancelJobsThread
= new CancelJobsThread( aThreads
);;
401 if ( !mpCancelJobsThread
->create() )
404 // ASSERT( false, "<FinalThreadManager::cancelAllJobs()> - thread to cancel jobs can't be setup --> synchron cancellation of jobs" );
405 delete mpCancelJobsThread
;
406 mpCancelJobsThread
= 0;
407 while ( !aThreads
.empty() )
409 aThreads
.front()->cancel();
410 aThreads
.pop_front();
416 mpCancelJobsThread
->addJobs( aThreads
);
421 // ::com::sun::star::frame::XTerminateListener
422 void SAL_CALL
FinalThreadManager::queryTermination( const css::lang::EventObject
& ) throw (css::frame::TerminationVetoException
, css::uno::RuntimeException
)
424 osl::MutexGuard
aGuard(maMutex
);
427 // Sleep 1 second to give the thread for job cancellation some time.
428 // Probably, all started threads have already finished its work.
429 if ( mpCancelJobsThread
!= 0 &&
430 !mpCancelJobsThread
->allJobsCancelled() )
432 TimeValue aSleepTime
;
433 aSleepTime
.Seconds
= 1;
434 aSleepTime
.Nanosec
= 0;
435 osl_waitThread( &aSleepTime
);
438 if ( mpCancelJobsThread
!= 0 &&
439 !mpCancelJobsThread
->allJobsCancelled() )
441 if ( mpTerminateOfficeThread
!= 0 )
443 if ( mpTerminateOfficeThread
->isRunning() )
445 mpTerminateOfficeThread
->StopOfficeTermination(); // thread kills itself.
449 delete mpTerminateOfficeThread
;
451 mpTerminateOfficeThread
= 0;
453 mpTerminateOfficeThread
= new TerminateOfficeThread( *mpCancelJobsThread
,
455 if ( !mpTerminateOfficeThread
->create() )
457 // ASSERT( false, "FinalThreadManager::queryTermination(..) - thread to terminate office can't be started!" );
458 delete mpTerminateOfficeThread
;
459 mpTerminateOfficeThread
= 0;
462 throw css::frame::TerminationVetoException();
465 mpPauseThreadStarting
= new SwPauseThreadStarting();
470 void SAL_CALL
FinalThreadManager::cancelTermination( const css::lang::EventObject
& ) throw (css::uno::RuntimeException
)
472 if ( mpPauseThreadStarting
!= 0 )
474 delete mpPauseThreadStarting
;
475 mpPauseThreadStarting
= 0;
481 void SAL_CALL
FinalThreadManager::notifyTermination( const css::lang::EventObject
& ) throw (css::uno::RuntimeException
)
483 if ( mpTerminateOfficeThread
!= 0 )
485 if ( mpTerminateOfficeThread
->isRunning() )
487 // ASSERT( false, "<FinalThreadManager::notifyTermination()> - office termination thread still running!" );
488 mpTerminateOfficeThread
->StopOfficeTermination(); // thread kills itself.
492 delete mpTerminateOfficeThread
;
494 mpTerminateOfficeThread
= 0;
497 if ( !maThreads
.empty() )
499 // ASSERT( false, "<FinalThreadManager::notifyTermination()> - still registered jobs are existing" );
503 if ( mpCancelJobsThread
!= 0 )
505 if ( !mpCancelJobsThread
->allJobsCancelled() )
507 // ASSERT( false, "<FinalThreadManager::notifyTermination()> - cancellation of registered jobs not yet finished -> wait for its finish" );
510 mpCancelJobsThread
->stopWhenAllJobsCancelled();
511 mpCancelJobsThread
->join();
512 delete mpCancelJobsThread
;
513 mpCancelJobsThread
= 0;
516 // get reference of this
517 css::uno::Reference
< css::uno::XInterface
> aOwnRef( static_cast< cppu::OWeakObject
* >( this ));
518 // notify <SwThreadJoiner> to release its reference
519 SwThreadJoiner::ReleaseThreadJoiner();
522 // ::com::sun:star::lang::XEventListener (inherited via com::sun::star::frame::XTerminateListener)
523 void SAL_CALL
FinalThreadManager::disposing( const css::lang::EventObject
& ) throw (css::uno::RuntimeException
)
525 // nothing to do, because instance doesn't hold any references of observed objects
528 // component helper namespace
529 namespace comp_FinalThreadManager
{
531 ::rtl::OUString SAL_CALL
_getImplementationName()
533 return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
534 "com.sun.star.util.comp.FinalThreadManager"));
537 css::uno::Sequence
< ::rtl::OUString
> SAL_CALL
_getSupportedServiceNames()
539 css::uno::Sequence
< ::rtl::OUString
> s(1);
540 s
[0] = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
541 "com.sun.star.util.JobManager"));
545 css::uno::Reference
< css::uno::XInterface
> SAL_CALL
_create(
546 const css::uno::Reference
< css::uno::XComponentContext
> & context
)
547 SAL_THROW((css::uno::Exception
))
549 return static_cast< ::cppu::OWeakObject
* >(new FinalThreadManager(context
));
552 } // closing component helper namespace