android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / core / docnode / finalthreadmanager.cxx
blob73a0feccfaff8c6e843c3e5ed6fb3536330e4aeb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <finalthreadmanager.hxx>
22 #include <osl/diagnose.h>
23 #include <osl/thread.hxx>
24 #include <pausethreadstarting.hxx>
25 #include <swthreadjoiner.hxx>
27 #include <com/sun/star/frame/Desktop.hpp>
28 #include <com/sun/star/frame/TerminationVetoException.hpp>
29 #include <rtl/ustring.hxx>
30 #include <cppuhelper/supportsservice.hxx>
31 #include <mutex>
32 #include <thread>
33 #include <utility>
35 /** thread to cancel a give list of cancellable jobs
37 helper class for FinalThreadManager
39 class CancelJobsThread : public osl::Thread
41 public:
42 explicit CancelJobsThread( std::list< css::uno::Reference< css::util::XCancellable > >&& rJobs )
43 : maJobs( std::move(rJobs) ),
44 mbAllJobsCancelled( false ),
45 mbStopped( false )
49 void addJobs( std::list< css::uno::Reference< css::util::XCancellable > >& rJobs );
50 bool allJobsCancelled() const;
51 void stopWhenAllJobsCancelled();
53 private:
54 bool existJobs() const;
56 css::uno::Reference< css::util::XCancellable > getNextJob();
58 bool stopped() const;
59 virtual void SAL_CALL run() override;
60 mutable std::mutex maMutex;
62 std::list< css::uno::Reference< css::util::XCancellable > > maJobs;
64 bool mbAllJobsCancelled;
65 bool mbStopped;
68 void CancelJobsThread::addJobs( std::list< css::uno::Reference< css::util::XCancellable > >& rJobs )
70 std::scoped_lock aGuard(maMutex);
72 maJobs.insert( maJobs.end(), rJobs.begin(), rJobs.end() );
73 mbAllJobsCancelled = !maJobs.empty();
76 bool CancelJobsThread::existJobs() const
78 std::scoped_lock aGuard(maMutex);
80 return !maJobs.empty();
83 bool CancelJobsThread::allJobsCancelled() const
85 std::scoped_lock aGuard(maMutex);
87 return maJobs.empty() && mbAllJobsCancelled;
90 void CancelJobsThread::stopWhenAllJobsCancelled()
92 std::scoped_lock aGuard(maMutex);
94 mbStopped = true;
97 css::uno::Reference< css::util::XCancellable > CancelJobsThread::getNextJob()
99 css::uno::Reference< css::util::XCancellable > xRet;
102 std::scoped_lock aGuard(maMutex);
104 if ( !maJobs.empty() )
106 xRet = maJobs.front();
107 maJobs.pop_front();
111 return xRet;
114 bool CancelJobsThread::stopped() const
116 std::scoped_lock aGuard(maMutex);
118 return mbStopped;
121 void SAL_CALL CancelJobsThread::run()
123 osl_setThreadName("sw CancelJobsThread");
125 while ( !stopped() )
127 while ( existJobs() )
129 css::uno::Reference< css::util::XCancellable > aJob( getNextJob() );
130 if ( aJob.is() )
131 aJob->cancel();
134 mbAllJobsCancelled = true;
137 std::this_thread::sleep_for(std::chrono::seconds(1));
142 /** thread to terminate office, when all jobs are cancelled.
144 helper class for FinalThreadManager
146 class TerminateOfficeThread : public osl::Thread
148 public:
149 TerminateOfficeThread( CancelJobsThread const & rCancelJobsThread,
150 css::uno::Reference< css::uno::XComponentContext > xContext )
151 : mrCancelJobsThread( rCancelJobsThread ),
152 mbStopOfficeTermination( false ),
153 mxContext(std::move( xContext ))
157 void StopOfficeTermination();
159 private:
160 virtual void SAL_CALL run() override;
161 virtual void SAL_CALL onTerminated() override;
162 bool OfficeTerminationStopped();
163 void PerformOfficeTermination();
165 osl::Mutex maMutex;
167 const CancelJobsThread& mrCancelJobsThread;
168 bool mbStopOfficeTermination;
170 css::uno::Reference< css::uno::XComponentContext > mxContext;
173 void TerminateOfficeThread::StopOfficeTermination()
175 osl::MutexGuard aGuard(maMutex);
177 mbStopOfficeTermination = true;
180 bool TerminateOfficeThread::OfficeTerminationStopped()
182 osl::MutexGuard aGuard(maMutex);
184 return mbStopOfficeTermination;
187 void SAL_CALL TerminateOfficeThread::run()
189 osl_setThreadName("sw TerminateOfficeThread");
191 while ( !OfficeTerminationStopped() )
193 osl::MutexGuard aGuard(maMutex);
195 if ( mrCancelJobsThread.allJobsCancelled() )
196 break;
199 if ( !OfficeTerminationStopped() )
200 PerformOfficeTermination();
203 void TerminateOfficeThread::PerformOfficeTermination()
205 css::uno::Reference< css::frame::XDesktop2 > xDesktop = css::frame::Desktop::create(mxContext);
207 css::uno::Reference< css::container::XElementAccess > xList = xDesktop->getFrames();
208 if ( !xList.is() )
210 OSL_FAIL( "<TerminateOfficeThread::PerformOfficeTermination()> - no XElementAccess!" );
211 return;
214 if ( !xList->hasElements() )
216 if ( !OfficeTerminationStopped() )
217 xDesktop->terminate();
221 void SAL_CALL TerminateOfficeThread::onTerminated()
223 if ( OfficeTerminationStopped() )
224 delete this;
227 FinalThreadManager::FinalThreadManager(css::uno::Reference< css::uno::XComponentContext > context)
228 : m_xContext(std::move(context)),
229 mpTerminateOfficeThread( nullptr ),
230 mbRegisteredAtDesktop( false )
235 void FinalThreadManager::registerAsListenerAtDesktop()
237 css::uno::Reference< css::frame::XDesktop2 > xDesktop = css::frame::Desktop::create(m_xContext);
238 xDesktop->addTerminateListener( css::uno::Reference< css::frame::XTerminateListener >( this ) );
241 FinalThreadManager::~FinalThreadManager()
243 if ( mpPauseThreadStarting )
245 mpPauseThreadStarting.reset();
248 if ( mpTerminateOfficeThread != nullptr )
250 mpTerminateOfficeThread->StopOfficeTermination(); // thread kills itself.
251 mpTerminateOfficeThread = nullptr;
254 if ( !maThreads.empty() )
256 OSL_FAIL( "<FinalThreadManager::~FinalThreadManager()> - still registered jobs are existing -> perform cancellation" );
257 cancelAllJobs();
260 if ( mpCancelJobsThread != nullptr )
262 if ( !mpCancelJobsThread->allJobsCancelled() )
263 OSL_FAIL( "<FinalThreadManager::~FinalThreadManager()> - cancellation of registered jobs not yet finished -> wait for its finish" );
265 mpCancelJobsThread->stopWhenAllJobsCancelled();
266 mpCancelJobsThread->join();
267 mpCancelJobsThread.reset();
271 // com.sun.star.uno.XServiceInfo:
272 OUString SAL_CALL FinalThreadManager::getImplementationName()
274 return "com.sun.star.util.comp.FinalThreadManager";
277 sal_Bool SAL_CALL FinalThreadManager::supportsService(OUString const & serviceName)
279 return cppu::supportsService(this, serviceName);
282 css::uno::Sequence< OUString > SAL_CALL FinalThreadManager::getSupportedServiceNames()
284 return { "com.sun.star.util.JobManager" };
287 // css::util::XJobManager:
288 void SAL_CALL FinalThreadManager::registerJob(const css::uno::Reference< css::util::XCancellable > & Job)
290 osl::MutexGuard aGuard(maMutex);
292 maThreads.push_back( Job );
294 if ( !mbRegisteredAtDesktop )
296 registerAsListenerAtDesktop();
297 mbRegisteredAtDesktop = true;
301 void SAL_CALL FinalThreadManager::releaseJob(const css::uno::Reference< css::util::XCancellable > & Job)
303 osl::MutexGuard aGuard(maMutex);
305 maThreads.remove( Job );
308 void SAL_CALL FinalThreadManager::cancelAllJobs()
310 std::list< css::uno::Reference< css::util::XCancellable > > aThreads;
312 osl::MutexGuard aGuard(maMutex);
314 aThreads.insert( aThreads.end(), maThreads.begin(), maThreads.end() );
315 maThreads.clear();
318 if ( aThreads.empty() )
319 return;
321 osl::MutexGuard aGuard(maMutex);
323 if ( mpCancelJobsThread == nullptr )
325 mpCancelJobsThread.reset(new CancelJobsThread( std::list(aThreads) ));
326 if ( !mpCancelJobsThread->create() )
328 mpCancelJobsThread.reset();
329 for (auto const& elem : aThreads)
331 elem->cancel();
333 aThreads.clear();
336 else
337 mpCancelJobsThread->addJobs( aThreads );
340 // css::frame::XTerminateListener
341 void SAL_CALL FinalThreadManager::queryTermination( const css::lang::EventObject& )
343 osl::MutexGuard aGuard(maMutex);
345 cancelAllJobs();
346 // Sleep 1 second to give the thread for job cancellation some time.
347 // Probably, all started threads have already finished its work.
348 if ( mpCancelJobsThread != nullptr &&
349 !mpCancelJobsThread->allJobsCancelled() )
351 std::this_thread::sleep_for(std::chrono::seconds(1));
354 if ( mpCancelJobsThread != nullptr &&
355 !mpCancelJobsThread->allJobsCancelled() )
357 if ( mpTerminateOfficeThread != nullptr )
359 if ( mpTerminateOfficeThread->isRunning() )
360 mpTerminateOfficeThread->StopOfficeTermination(); // thread kills itself.
361 else
362 delete mpTerminateOfficeThread;
364 mpTerminateOfficeThread = nullptr;
366 mpTerminateOfficeThread = new TerminateOfficeThread( *mpCancelJobsThread,
367 m_xContext );
368 if ( !mpTerminateOfficeThread->create() )
370 delete mpTerminateOfficeThread;
371 mpTerminateOfficeThread = nullptr;
374 throw css::frame::TerminationVetoException();
377 mpPauseThreadStarting.reset(new SwPauseThreadStarting());
380 void SAL_CALL FinalThreadManager::cancelTermination( const css::lang::EventObject& )
382 mpPauseThreadStarting.reset();
385 void SAL_CALL FinalThreadManager::notifyTermination( const css::lang::EventObject& )
387 if ( mpTerminateOfficeThread != nullptr )
389 if ( mpTerminateOfficeThread->isRunning() )
390 mpTerminateOfficeThread->StopOfficeTermination(); // thread kills itself.
391 else
392 delete mpTerminateOfficeThread;
394 mpTerminateOfficeThread = nullptr;
397 if ( !maThreads.empty() )
398 cancelAllJobs();
400 if ( mpCancelJobsThread != nullptr )
402 mpCancelJobsThread->stopWhenAllJobsCancelled();
403 mpCancelJobsThread->join();
404 mpCancelJobsThread.reset();
407 // get reference of this
408 css::uno::Reference< css::uno::XInterface > aOwnRef( static_cast< cppu::OWeakObject* >( this ));
409 // notify <SwThreadJoiner> to release its reference
410 SwThreadJoiner::ReleaseThreadJoiner();
413 // ::com::sun:star::lang::XEventListener (inherited via css::frame::XTerminateListener)
414 void SAL_CALL FinalThreadManager::disposing( const css::lang::EventObject& )
416 // nothing to do, because instance doesn't hold any references of observed objects
419 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
420 com_sun_star_util_comp_FinalThreadManager_get_implementation(css::uno::XComponentContext* context,
421 css::uno::Sequence<css::uno::Any> const &)
423 return cppu::acquire(new FinalThreadManager(context));
426 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */