Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : : #include <finalthreadmanager.hxx>
29 : :
30 : : #include <osl/thread.hxx>
31 : : #include <pausethreadstarting.hxx>
32 : : #include <swthreadjoiner.hxx>
33 : :
34 : : #include <com/sun/star/frame/XDesktop.hpp>
35 : : #include <rtl/ustring.hxx>
36 : : #include <com/sun/star/frame/XFramesSupplier.hpp>
37 : :
38 : : namespace css = ::com::sun::star;
39 : :
40 : : /** thread to cancel a give list of cancellable jobs
41 : :
42 : : helper class for FinalThreadManager
43 : :
44 : : @author OD
45 : : */
46 : : class CancelJobsThread : public osl::Thread
47 : : {
48 : : public:
49 : 0 : CancelJobsThread( std::list< css::uno::Reference< css::util::XCancellable > > aJobs )
50 : : : osl::Thread(),
51 : : maMutex(),
52 : : maJobs( aJobs ),
53 : : mbAllJobsCancelled( false ),
54 [ # # ][ # # ]: 0 : mbStopped( false )
55 : : {
56 : 0 : }
57 : :
58 [ # # ][ # # ]: 0 : virtual ~CancelJobsThread() {}
59 : :
60 : : void addJobs( std::list< css::uno::Reference< css::util::XCancellable > >& rJobs );
61 : : bool allJobsCancelled() const;
62 : : void stopWhenAllJobsCancelled();
63 : :
64 : : private:
65 : : bool existJobs() const;
66 : :
67 : : css::uno::Reference< css::util::XCancellable > getNextJob();
68 : :
69 : : bool stopped() const;
70 : : virtual void SAL_CALL run();
71 : : mutable osl::Mutex maMutex;
72 : :
73 : : std::list< css::uno::Reference< css::util::XCancellable > > maJobs;
74 : :
75 : : bool mbAllJobsCancelled;
76 : : bool mbStopped;
77 : : };
78 : :
79 : 0 : void CancelJobsThread::addJobs( std::list< css::uno::Reference< css::util::XCancellable > >& rJobs )
80 : : {
81 [ # # ]: 0 : osl::MutexGuard aGuard(maMutex);
82 : :
83 [ # # ]: 0 : maJobs.insert( maJobs.end(), rJobs.begin(), rJobs.end() );
84 [ # # ]: 0 : mbAllJobsCancelled = !maJobs.empty();
85 : 0 : }
86 : :
87 : 0 : bool CancelJobsThread::existJobs() const
88 : : {
89 [ # # ]: 0 : osl::MutexGuard aGuard(maMutex);
90 : :
91 [ # # ]: 0 : return !maJobs.empty();
92 : : }
93 : :
94 : 0 : bool CancelJobsThread::allJobsCancelled() const
95 : : {
96 [ # # ]: 0 : osl::MutexGuard aGuard(maMutex);
97 : :
98 [ # # ][ # # ]: 0 : return maJobs.empty() && mbAllJobsCancelled;
[ # # ]
99 : : }
100 : 0 : void CancelJobsThread::stopWhenAllJobsCancelled()
101 : : {
102 [ # # ]: 0 : osl::MutexGuard aGuard(maMutex);
103 : :
104 [ # # ]: 0 : mbStopped = true;
105 : 0 : }
106 : :
107 : 0 : css::uno::Reference< css::util::XCancellable > CancelJobsThread::getNextJob()
108 : : {
109 : 0 : css::uno::Reference< css::util::XCancellable > xRet;
110 : :
111 : : {
112 [ # # ]: 0 : osl::MutexGuard aGuard(maMutex);
113 : :
114 [ # # ]: 0 : if ( !maJobs.empty() )
115 : : {
116 [ # # ][ # # ]: 0 : xRet = maJobs.front();
117 [ # # ]: 0 : maJobs.pop_front();
118 [ # # ]: 0 : }
119 : : }
120 : :
121 : 0 : return xRet;
122 : : }
123 : :
124 : 0 : bool CancelJobsThread::stopped() const
125 : : {
126 [ # # ]: 0 : osl::MutexGuard aGuard(maMutex);
127 : :
128 [ # # ]: 0 : return mbStopped;
129 : : }
130 : :
131 : 0 : void SAL_CALL CancelJobsThread::run()
132 : : {
133 [ # # ]: 0 : while ( !stopped() )
134 : : {
135 [ # # ]: 0 : while ( existJobs() )
136 : : {
137 [ # # ]: 0 : css::uno::Reference< css::util::XCancellable > aJob( getNextJob() );
138 [ # # ]: 0 : if ( aJob.is() )
139 [ # # ][ # # ]: 0 : aJob->cancel();
140 : 0 : }
141 : :
142 : 0 : mbAllJobsCancelled = true;
143 : :
144 : : {
145 : : TimeValue aSleepTime;
146 : 0 : aSleepTime.Seconds = 1;
147 : 0 : aSleepTime.Nanosec = 0;
148 [ # # ]: 0 : osl_waitThread( &aSleepTime );
149 : : }
150 : : }
151 : 0 : }
152 : :
153 : : /** thread to terminate office, when all jobs are cancelled.
154 : :
155 : : helper class for FinalThreadManager
156 : :
157 : : @author OD
158 : : */
159 : : class TerminateOfficeThread : public osl::Thread
160 : : {
161 : : public:
162 : 0 : TerminateOfficeThread( CancelJobsThread& rCancelJobsThread,
163 : : css::uno::Reference< css::uno::XComponentContext > const & xContext )
164 : : : osl::Thread(),
165 : : maMutex(),
166 : : mrCancelJobsThread( rCancelJobsThread ),
167 : : mbStopOfficeTermination( false ),
168 [ # # ]: 0 : mxContext( xContext )
169 : : {
170 : 0 : }
171 : :
172 [ # # ][ # # ]: 0 : virtual ~TerminateOfficeThread() {}
173 : : void StopOfficeTermination();
174 : :
175 : : private:
176 : : virtual void SAL_CALL run();
177 : : virtual void SAL_CALL onTerminated();
178 : : bool OfficeTerminationStopped();
179 : : void PerformOfficeTermination();
180 : :
181 : : osl::Mutex maMutex;
182 : :
183 : : const CancelJobsThread& mrCancelJobsThread;
184 : : bool mbStopOfficeTermination;
185 : :
186 : : css::uno::Reference< css::uno::XComponentContext > mxContext;
187 : : };
188 : :
189 : 0 : void TerminateOfficeThread::StopOfficeTermination()
190 : : {
191 [ # # ]: 0 : osl::MutexGuard aGuard(maMutex);
192 : :
193 [ # # ]: 0 : mbStopOfficeTermination = true;
194 : 0 : }
195 : :
196 : 0 : bool TerminateOfficeThread::OfficeTerminationStopped()
197 : : {
198 [ # # ]: 0 : osl::MutexGuard aGuard(maMutex);
199 : :
200 [ # # ]: 0 : return mbStopOfficeTermination;
201 : : }
202 : :
203 : 0 : void SAL_CALL TerminateOfficeThread::run()
204 : : {
205 [ # # ]: 0 : while ( !OfficeTerminationStopped() )
206 : : {
207 [ # # ]: 0 : osl::MutexGuard aGuard(maMutex);
208 : :
209 [ # # ][ # # ]: 0 : if ( mrCancelJobsThread.allJobsCancelled() )
210 : : break;
211 [ # # ][ # # ]: 0 : }
212 : :
213 [ # # ]: 0 : if ( !OfficeTerminationStopped() )
214 : 0 : PerformOfficeTermination();
215 : 0 : }
216 : :
217 : 0 : void TerminateOfficeThread::PerformOfficeTermination()
218 : : {
219 : : css::uno::Reference< css::frame::XFramesSupplier > xTasksSupplier(
220 [ # # ][ # # ]: 0 : mxContext->getServiceManager()->createInstanceWithContext(
[ # # ]
221 : : ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.frame.Desktop") ),
222 : 0 : mxContext ),
223 [ # # ][ # # ]: 0 : css::uno::UNO_QUERY );
[ # # ]
224 [ # # ]: 0 : if ( !xTasksSupplier.is() )
225 : : {
226 : : OSL_FAIL( "<TerminateOfficeThread::PerformOfficeTermination()> - no XFramesSupplier!" );
227 : : return;
228 : : }
229 : :
230 [ # # ][ # # ]: 0 : css::uno::Reference< css::container::XElementAccess > xList( xTasksSupplier->getFrames(), css::uno::UNO_QUERY );
[ # # ]
231 [ # # ]: 0 : if ( !xList.is() )
232 : : {
233 : : OSL_FAIL( "<TerminateOfficeThread::PerformOfficeTermination()> - no XElementAccess!" );
234 : : return;
235 : : }
236 : :
237 [ # # ][ # # ]: 0 : if ( !xList->hasElements() )
[ # # ]
238 : : {
239 [ # # ]: 0 : css::uno::Reference< css::frame::XDesktop > xDesktop( xTasksSupplier, css::uno::UNO_QUERY );
240 [ # # ][ # # ]: 0 : if ( xDesktop.is() && !OfficeTerminationStopped() )
[ # # ][ # # ]
241 [ # # ][ # # ]: 0 : xDesktop->terminate();
242 [ # # ][ # # ]: 0 : }
243 : : }
244 : :
245 : 0 : void SAL_CALL TerminateOfficeThread::onTerminated()
246 : : {
247 [ # # ]: 0 : if ( OfficeTerminationStopped() )
248 [ # # ]: 0 : delete this;
249 : 0 : }
250 : :
251 : :
252 : : /** class FinalThreadManager
253 : :
254 : : @author OD
255 : : */
256 : 2 : FinalThreadManager::FinalThreadManager(css::uno::Reference< css::uno::XComponentContext > const & context)
257 : : : m_xContext(context),
258 : : maMutex(),
259 : : maThreads(),
260 : : mpCancelJobsThread( 0 ),
261 : : mpTerminateOfficeThread( 0 ),
262 : : mpPauseThreadStarting( 0 ),
263 [ + - ][ + - ]: 2 : mbRegisteredAtDesktop( false )
264 : : {
265 : :
266 : 2 : }
267 : :
268 : 2 : void FinalThreadManager::registerAsListenerAtDesktop()
269 : : {
270 : : css::uno::Reference< css::frame::XDesktop > xDesktop(
271 [ + - ][ + - ]: 4 : m_xContext->getServiceManager()->createInstanceWithContext(
[ + - ]
272 : : ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.frame.Desktop") ),
273 : 2 : m_xContext ),
274 [ + - ][ + - ]: 2 : css::uno::UNO_QUERY );
[ + - ]
275 : :
276 [ + - ]: 2 : if ( xDesktop.is() )
277 [ + - ][ + - ]: 2 : xDesktop->addTerminateListener( css::uno::Reference< css::frame::XTerminateListener >( static_cast< cppu::OWeakObject* >( this ), css::uno::UNO_QUERY ) );
[ + - ]
278 : 2 : }
279 : :
280 [ + - ]: 2 : FinalThreadManager::~FinalThreadManager()
281 : : {
282 [ + - ]: 2 : if ( mpPauseThreadStarting != 0 )
283 : : {
284 [ + - ][ + - ]: 2 : delete mpPauseThreadStarting;
285 : 2 : mpPauseThreadStarting = 0;
286 : : }
287 : :
288 [ - + ]: 2 : if ( mpTerminateOfficeThread != 0 )
289 : : {
290 [ # # ]: 0 : mpTerminateOfficeThread->StopOfficeTermination(); // thread kills itself.
291 : 0 : mpTerminateOfficeThread = 0;
292 : : }
293 : :
294 [ - + ]: 2 : if ( !maThreads.empty() )
295 : : {
296 : : OSL_FAIL( "<FinalThreadManager::~FinalThreadManager()> - still registered jobs are existing -> perform cancellation" );
297 [ # # ]: 0 : cancelAllJobs();
298 : : }
299 : :
300 [ - + ]: 2 : if ( mpCancelJobsThread != 0 )
301 : : {
302 [ # # ]: 0 : if ( !mpCancelJobsThread->allJobsCancelled() )
303 : : OSL_FAIL( "<FinalThreadManager::~FinalThreadManager()> - cancellation of registered jobs not yet finished -> wait for its finish" );
304 : :
305 [ # # ]: 0 : mpCancelJobsThread->stopWhenAllJobsCancelled();
306 [ # # ]: 0 : mpCancelJobsThread->join();
307 [ # # ][ # # ]: 0 : delete mpCancelJobsThread;
308 : 0 : mpCancelJobsThread = 0;
309 : : }
310 [ - + ]: 4 : }
311 : :
312 : : // com.sun.star.uno.XServiceInfo:
313 : 2 : ::rtl::OUString SAL_CALL FinalThreadManager::getImplementationName() throw (css::uno::RuntimeException)
314 : : {
315 : 2 : return comp_FinalThreadManager::_getImplementationName();
316 : : }
317 : :
318 : 0 : ::sal_Bool SAL_CALL FinalThreadManager::supportsService(::rtl::OUString const & serviceName) throw (css::uno::RuntimeException)
319 : : {
320 [ # # ]: 0 : css::uno::Sequence< ::rtl::OUString > serviceNames = comp_FinalThreadManager::_getSupportedServiceNames();
321 [ # # ]: 0 : for (::sal_Int32 i = 0; i < serviceNames.getLength(); ++i) {
322 [ # # ][ # # ]: 0 : if (serviceNames[i] == serviceName)
323 : 0 : return sal_True;
324 : : }
325 [ # # ]: 0 : return sal_False;
326 : : }
327 : :
328 : 0 : css::uno::Sequence< ::rtl::OUString > SAL_CALL FinalThreadManager::getSupportedServiceNames() throw (css::uno::RuntimeException)
329 : : {
330 : 0 : return comp_FinalThreadManager::_getSupportedServiceNames();
331 : : }
332 : :
333 : : // ::com::sun::star::util::XJobManager:
334 : 8 : void SAL_CALL FinalThreadManager::registerJob(const css::uno::Reference< css::util::XCancellable > & Job) throw (css::uno::RuntimeException)
335 : : {
336 [ + - ]: 8 : osl::MutexGuard aGuard(maMutex);
337 : :
338 [ + - ]: 8 : maThreads.push_back( Job );
339 : :
340 [ + + ]: 8 : if ( !mbRegisteredAtDesktop )
341 : : {
342 [ + - ]: 2 : registerAsListenerAtDesktop();
343 : 2 : mbRegisteredAtDesktop = true;
344 [ + - ]: 8 : }
345 : 8 : }
346 : :
347 : 8 : void SAL_CALL FinalThreadManager::releaseJob(const css::uno::Reference< css::util::XCancellable > & Job) throw (css::uno::RuntimeException)
348 : : {
349 [ + - ]: 8 : osl::MutexGuard aGuard(maMutex);
350 : :
351 [ + - ][ + - ]: 8 : maThreads.remove( Job );
352 : 8 : }
353 : :
354 : 2 : void SAL_CALL FinalThreadManager::cancelAllJobs() throw (css::uno::RuntimeException)
355 : : {
356 [ + - ]: 2 : std::list< css::uno::Reference< css::util::XCancellable > > aThreads;
357 : : {
358 [ + - ]: 2 : osl::MutexGuard aGuard(maMutex);
359 : :
360 [ + - ]: 2 : aThreads.insert( aThreads.end(), maThreads.begin(), maThreads.end() );
361 [ + - ]: 2 : maThreads.clear();
362 : : }
363 : :
364 [ - + ]: 2 : if ( !aThreads.empty() )
365 : : {
366 [ # # ]: 0 : osl::MutexGuard aGuard(maMutex);
367 : :
368 [ # # ]: 0 : if ( mpCancelJobsThread == 0 )
369 : : {
370 [ # # ][ # # ]: 0 : mpCancelJobsThread = new CancelJobsThread( aThreads );;
371 [ # # ][ # # ]: 0 : if ( !mpCancelJobsThread->create() )
372 : : {
373 [ # # ][ # # ]: 0 : delete mpCancelJobsThread;
374 : 0 : mpCancelJobsThread = 0;
375 [ # # ]: 0 : while ( !aThreads.empty() )
376 : : {
377 [ # # ][ # # ]: 0 : aThreads.front()->cancel();
[ # # ]
378 [ # # ]: 0 : aThreads.pop_front();
379 : : }
380 : : }
381 : : }
382 : : else
383 [ # # ][ # # ]: 0 : mpCancelJobsThread->addJobs( aThreads );
384 : 2 : }
385 : 2 : }
386 : :
387 : : // ::com::sun::star::frame::XTerminateListener
388 : 2 : void SAL_CALL FinalThreadManager::queryTermination( const css::lang::EventObject& ) throw (css::frame::TerminationVetoException, css::uno::RuntimeException)
389 : : {
390 [ + - ]: 2 : osl::MutexGuard aGuard(maMutex);
391 : :
392 [ + - ]: 2 : cancelAllJobs();
393 : : // Sleep 1 second to give the thread for job cancellation some time.
394 : : // Probably, all started threads have already finished its work.
395 [ - + ][ # # ]: 2 : if ( mpCancelJobsThread != 0 &&
[ - + ]
396 [ # # ]: 0 : !mpCancelJobsThread->allJobsCancelled() )
397 : : {
398 : : TimeValue aSleepTime;
399 : 0 : aSleepTime.Seconds = 1;
400 : 0 : aSleepTime.Nanosec = 0;
401 [ # # ]: 0 : osl_waitThread( &aSleepTime );
402 : : }
403 : :
404 [ - + ][ # # ]: 2 : if ( mpCancelJobsThread != 0 &&
[ - + ]
405 [ # # ]: 0 : !mpCancelJobsThread->allJobsCancelled() )
406 : : {
407 [ # # ]: 0 : 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 : : mpTerminateOfficeThread = new TerminateOfficeThread( *mpCancelJobsThread,
417 [ # # ]: 0 : m_xContext );
418 [ # # ][ # # ]: 0 : if ( !mpTerminateOfficeThread->create() )
419 : : {
420 [ # # ][ # # ]: 0 : delete mpTerminateOfficeThread;
421 : 0 : mpTerminateOfficeThread = 0;
422 : : }
423 : :
424 [ # # ]: 0 : throw css::frame::TerminationVetoException();
425 : : }
426 : :
427 [ + - ][ + - ]: 2 : mpPauseThreadStarting = new SwPauseThreadStarting();
428 : :
429 [ + - ]: 2 : return;
430 : : }
431 : :
432 : 0 : void SAL_CALL FinalThreadManager::cancelTermination( const css::lang::EventObject& ) throw (css::uno::RuntimeException)
433 : : {
434 [ # # ]: 0 : if ( mpPauseThreadStarting != 0 )
435 : : {
436 [ # # ]: 0 : delete mpPauseThreadStarting;
437 : 0 : mpPauseThreadStarting = 0;
438 : : }
439 : :
440 : 0 : return;
441 : : }
442 : :
443 : 2 : void SAL_CALL FinalThreadManager::notifyTermination( const css::lang::EventObject& ) throw (css::uno::RuntimeException)
444 : : {
445 [ - + ]: 2 : if ( mpTerminateOfficeThread != 0 )
446 : : {
447 [ # # ][ # # ]: 0 : if ( mpTerminateOfficeThread->isRunning() )
448 [ # # ]: 0 : mpTerminateOfficeThread->StopOfficeTermination(); // thread kills itself.
449 : : else
450 [ # # ][ # # ]: 0 : delete mpTerminateOfficeThread;
451 : :
452 : 0 : mpTerminateOfficeThread = 0;
453 : : }
454 : :
455 [ - + ]: 2 : if ( !maThreads.empty() )
456 [ # # ]: 0 : cancelAllJobs();
457 : :
458 [ - + ]: 2 : if ( mpCancelJobsThread != 0 )
459 : : {
460 [ # # ]: 0 : mpCancelJobsThread->stopWhenAllJobsCancelled();
461 [ # # ]: 0 : mpCancelJobsThread->join();
462 [ # # ][ # # ]: 0 : delete mpCancelJobsThread;
463 : 0 : mpCancelJobsThread = 0;
464 : : }
465 : :
466 : : // get reference of this
467 [ + - ]: 2 : css::uno::Reference< css::uno::XInterface > aOwnRef( static_cast< cppu::OWeakObject* >( this ));
468 : : // notify <SwThreadJoiner> to release its reference
469 [ + - ]: 2 : SwThreadJoiner::ReleaseThreadJoiner();
470 : 2 : }
471 : :
472 : : // ::com::sun:star::lang::XEventListener (inherited via com::sun::star::frame::XTerminateListener)
473 : 0 : void SAL_CALL FinalThreadManager::disposing( const css::lang::EventObject& ) throw (css::uno::RuntimeException)
474 : : {
475 : : // nothing to do, because instance doesn't hold any references of observed objects
476 : 0 : }
477 : :
478 : : // component helper namespace
479 : : namespace comp_FinalThreadManager {
480 : :
481 : 6 : ::rtl::OUString SAL_CALL _getImplementationName()
482 : : {
483 : : return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
484 : 6 : "com.sun.star.util.comp.FinalThreadManager"));
485 : : }
486 : :
487 : 2 : css::uno::Sequence< ::rtl::OUString > SAL_CALL _getSupportedServiceNames()
488 : : {
489 : 2 : css::uno::Sequence< ::rtl::OUString > s(1);
490 [ + - ]: 2 : s[0] = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
491 [ + - ]: 4 : "com.sun.star.util.JobManager"));
492 : 2 : return s;
493 : : }
494 : :
495 : 2 : css::uno::Reference< css::uno::XInterface > SAL_CALL _create(
496 : : const css::uno::Reference< css::uno::XComponentContext > & context)
497 : : SAL_THROW((css::uno::Exception))
498 : : {
499 [ + - ]: 2 : return static_cast< ::cppu::OWeakObject * >(new FinalThreadManager(context));
500 : : }
501 : :
502 : : } // closing component helper namespace
503 : :
504 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|