diff options
author | Michael Stahl <mstahl@redhat.com> | 2017-05-24 16:14:56 +0200 |
---|---|---|
committer | Andras Timar <andras.timar@collabora.com> | 2017-05-30 09:41:22 +0200 |
commit | 356e3ab9945e36fae7a07bb1c4948df5686236cf (patch) | |
tree | cb84f66a4d947dc52c1f0e3c2494bc2b690a5323 /sdext | |
parent | b6218e94f0bf546ac065be3f874ccd47c9381c78 (diff) |
rhbz#1425304 sdext: join TimerScheduler thread before shutdown
Use a osl::Condition to interrupt the waiting thread, and join it.
Change-Id: I638a2495afd082446c39faf9362578bd0f758d04
(cherry picked from commit 15b033d1dd09cd1898a994a0f12e38ed5cf847cb)
Reviewed-on: https://gerrit.libreoffice.org/37992
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Miklos Vajna <vmiklos@collabora.co.uk>
(cherry picked from commit 1a14a0404ef02a76cfc3b6bfd50b1c78bb150d45)
Diffstat (limited to 'sdext')
-rw-r--r-- | sdext/source/presenter/PresenterScrollBar.cxx | 1 | ||||
-rw-r--r-- | sdext/source/presenter/PresenterScrollBar.hxx | 3 | ||||
-rw-r--r-- | sdext/source/presenter/PresenterTextView.cxx | 6 | ||||
-rw-r--r-- | sdext/source/presenter/PresenterTextView.hxx | 2 | ||||
-rw-r--r-- | sdext/source/presenter/PresenterTimer.cxx | 99 | ||||
-rw-r--r-- | sdext/source/presenter/PresenterTimer.hxx | 2 |
6 files changed, 104 insertions, 9 deletions
diff --git a/sdext/source/presenter/PresenterScrollBar.cxx b/sdext/source/presenter/PresenterScrollBar.cxx index 8cba1bcafa01..831c0ec274bb 100644 --- a/sdext/source/presenter/PresenterScrollBar.cxx +++ b/sdext/source/presenter/PresenterScrollBar.cxx @@ -802,6 +802,7 @@ void PresenterScrollBar::MousePressRepeater::Start (const PresenterScrollBar::Ar // Schedule repeated executions. auto pThis(shared_from_this()); mnMousePressRepeaterTaskId = PresenterTimer::ScheduleRepeatedTask ( + mpScrollBar->GetComponentContext(), [pThis] (TimeValue const& rTime) { return pThis->Callback(rTime); }, 500000000, 250000000); diff --git a/sdext/source/presenter/PresenterScrollBar.hxx b/sdext/source/presenter/PresenterScrollBar.hxx index 7706ce4ea5aa..1c51194e897b 100644 --- a/sdext/source/presenter/PresenterScrollBar.hxx +++ b/sdext/source/presenter/PresenterScrollBar.hxx @@ -60,6 +60,9 @@ public: virtual void SAL_CALL disposing() override; + css::uno::Reference<css::uno::XComponentContext> const& + GetComponentContext() { return mxComponentContext; } + void SetVisible (const bool bIsVisible); /** Set the bounding box of the scroll bar. diff --git a/sdext/source/presenter/PresenterTextView.cxx b/sdext/source/presenter/PresenterTextView.cxx index 8e3800b46479..1946696b4b89 100644 --- a/sdext/source/presenter/PresenterTextView.cxx +++ b/sdext/source/presenter/PresenterTextView.cxx @@ -73,6 +73,7 @@ PresenterTextView::PresenterTextView ( mpFont(), maParagraphs(), mpCaret(new PresenterTextCaret( + rxContext, [this] (sal_Int32 const nParagraphIndex, sal_Int32 const nCharacterIndex) { return this->GetCaretBounds(nParagraphIndex, nCharacterIndex); }, rInvalidator)), @@ -1077,9 +1078,11 @@ void PresenterTextParagraph::SetupCellArray ( //===== PresenterTextCaret ================================================---- PresenterTextCaret::PresenterTextCaret ( + uno::Reference<uno::XComponentContext> const& xContext, const ::std::function<css::awt::Rectangle (const sal_Int32,const sal_Int32)>& rCharacterBoundsAccess, const ::std::function<void (const css::awt::Rectangle&)>& rInvalidator) - : mnParagraphIndex(-1), + : m_xContext(xContext) + , mnParagraphIndex(-1), mnCharacterIndex(-1), mnCaretBlinkTaskId(0), mbIsCaretVisible(false), @@ -1100,6 +1103,7 @@ void PresenterTextCaret::ShowCaret() if (mnCaretBlinkTaskId == 0) { mnCaretBlinkTaskId = PresenterTimer::ScheduleRepeatedTask ( + m_xContext, [this] (TimeValue const&) { return this->InvertCaret(); }, CaretBlinkIntervall, CaretBlinkIntervall); diff --git a/sdext/source/presenter/PresenterTextView.hxx b/sdext/source/presenter/PresenterTextView.hxx index b56bd5a85f31..9fc7fd663e1f 100644 --- a/sdext/source/presenter/PresenterTextView.hxx +++ b/sdext/source/presenter/PresenterTextView.hxx @@ -41,6 +41,7 @@ class PresenterTextCaret { public: PresenterTextCaret ( + css::uno::Reference<css::uno::XComponentContext> const& xContext, const ::std::function<css::awt::Rectangle (const sal_Int32,const sal_Int32)>& rCharacterBoundsAccess, const ::std::function<void (const css::awt::Rectangle&)>& @@ -69,6 +70,7 @@ public: const css::awt::Rectangle& GetBounds() const; private: + css::uno::Reference<css::uno::XComponentContext> const& m_xContext; sal_Int32 mnParagraphIndex; sal_Int32 mnCharacterIndex; sal_Int32 mnCaretBlinkTaskId; diff --git a/sdext/source/presenter/PresenterTimer.cxx b/sdext/source/presenter/PresenterTimer.cxx index e9d3117ba323..6d4897642c42 100644 --- a/sdext/source/presenter/PresenterTimer.cxx +++ b/sdext/source/presenter/PresenterTimer.cxx @@ -18,10 +18,15 @@ */ #include "PresenterTimer.hxx" + #include <com/sun/star/lang/XMultiComponentFactory.hpp> #include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/frame/Desktop.hpp> +#include <com/sun/star/frame/XTerminateListener.hpp> + #include <osl/doublecheckedlocking.h> #include <osl/thread.hxx> +#include <osl/conditn.hxx> #include <algorithm> #include <iterator> @@ -71,7 +76,8 @@ class TimerScheduler public ::osl::Thread { public: - static std::shared_ptr<TimerScheduler> Instance(); + static std::shared_ptr<TimerScheduler> Instance( + uno::Reference<uno::XComponentContext> const& xContext); static SharedTimerTask CreateTimerTask ( const PresenterTimer::Task& rTask, const TimeValue& rDueTime, @@ -90,6 +96,9 @@ public: static sal_Int64 ConvertFromTimeValue ( const TimeValue& rTimeValue); + static void NotifyTermination(); + static bool HasInstance() { return mpInstance != nullptr; } + private: static std::shared_ptr<TimerScheduler> mpInstance; static ::osl::Mutex maInstanceMutex; @@ -101,8 +110,10 @@ private: TaskContainer maScheduledTasks; ::osl::Mutex maCurrentTaskMutex; SharedTimerTask mpCurrentTask; + ::osl::Condition m_Shutdown; - TimerScheduler(); + TimerScheduler( + uno::Reference<uno::XComponentContext> const& xContext); virtual ~TimerScheduler() override; class Deleter {public: void operator () (TimerScheduler* pScheduler) { delete pScheduler; } }; friend class Deleter; @@ -111,15 +122,42 @@ private: virtual void SAL_CALL onTerminated() override { mpLateDestroy.reset(); } }; +class TerminateListener + : public ::cppu::WeakImplHelper<frame::XTerminateListener> +{ + virtual ~TerminateListener() override + { + assert(!TimerScheduler::HasInstance()); + } + + virtual void SAL_CALL disposing(lang::EventObject const&) + throw (uno::RuntimeException, std::exception) override + { + } + + virtual void SAL_CALL queryTermination(lang::EventObject const&) + throw (uno::RuntimeException, std::exception) override + { + } + + virtual void SAL_CALL notifyTermination(lang::EventObject const&) + throw (uno::RuntimeException, std::exception) override + { + TimerScheduler::NotifyTermination(); + } +}; + } // end of anonymous namespace //===== PresenterTimer ======================================================== sal_Int32 PresenterTimer::ScheduleRepeatedTask ( + const uno::Reference<uno::XComponentContext>& xContext, const Task& rTask, const sal_Int64 nDelay, const sal_Int64 nIntervall) { + assert(xContext.is()); TimeValue aCurrentTime; if (TimerScheduler::GetCurrentTime(aCurrentTime)) { @@ -128,7 +166,7 @@ sal_Int32 PresenterTimer::ScheduleRepeatedTask ( aDueTime, TimerScheduler::ConvertFromTimeValue (aCurrentTime) + nDelay); SharedTimerTask pTask (TimerScheduler::CreateTimerTask(rTask, aDueTime, nIntervall)); - TimerScheduler::Instance()->ScheduleTask(pTask); + TimerScheduler::Instance(xContext)->ScheduleTask(pTask); return pTask->mnTaskId; } @@ -137,7 +175,11 @@ sal_Int32 PresenterTimer::ScheduleRepeatedTask ( void PresenterTimer::CancelTask (const sal_Int32 nTaskId) { - return TimerScheduler::Instance()->CancelTask(nTaskId); + auto const pInstance(TimerScheduler::Instance(nullptr)); + if (pInstance) + { + pInstance->CancelTask(nTaskId); + } } //===== TimerScheduler ======================================================== @@ -146,23 +188,33 @@ std::shared_ptr<TimerScheduler> TimerScheduler::mpInstance; ::osl::Mutex TimerScheduler::maInstanceMutex; sal_Int32 TimerScheduler::mnTaskId = PresenterTimer::NotAValidTaskId; -std::shared_ptr<TimerScheduler> TimerScheduler::Instance() +std::shared_ptr<TimerScheduler> TimerScheduler::Instance( + uno::Reference<uno::XComponentContext> const& xContext) { ::osl::MutexGuard aGuard (maInstanceMutex); if (mpInstance.get() == nullptr) { - mpInstance.reset(new TimerScheduler(), TimerScheduler::Deleter()); + if (!xContext.is()) + return nullptr; + mpInstance.reset(new TimerScheduler(xContext), TimerScheduler::Deleter()); mpInstance->create(); } return mpInstance; } -TimerScheduler::TimerScheduler() +TimerScheduler::TimerScheduler( + uno::Reference<uno::XComponentContext> const& xContext) : maTaskContainerMutex(), maScheduledTasks(), maCurrentTaskMutex(), mpCurrentTask() { + uno::Reference<frame::XDesktop> const xDesktop( + frame::Desktop::create(xContext)); + uno::Reference<frame::XTerminateListener> const xListener( + new TerminateListener); + // assuming the desktop can take ownership + xDesktop->addTerminateListener(xListener); } TimerScheduler::~TimerScheduler() @@ -222,6 +274,33 @@ void TimerScheduler::CancelTask (const sal_Int32 nTaskId) // Let the main-loop cleanup in its own time } +void TimerScheduler::NotifyTermination() +{ + std::shared_ptr<TimerScheduler> const pInstance(TimerScheduler::mpInstance); + if (!pInstance) + { + return; + } + + { + ::osl::MutexGuard aGuard(pInstance->maTaskContainerMutex); + pInstance->maScheduledTasks.clear(); + } + + { + ::osl::MutexGuard aGuard(pInstance->maCurrentTaskMutex); + if (pInstance->mpCurrentTask) + { + pInstance->mpCurrentTask->mbIsCanceled = true; + } + } + + pInstance->m_Shutdown.set(); + + // rhbz#1425304 join thread before shutdown + pInstance->join(); +} + void SAL_CALL TimerScheduler::run() { osl_setThreadName("sdext::presenter::TimerScheduler"); @@ -269,7 +348,8 @@ void SAL_CALL TimerScheduler::run() // Wait until the first task becomes due. TimeValue aTimeValue; ConvertToTimeValue(aTimeValue, nDifference); - wait(aTimeValue); + // wait on condition variable, so the thread can be stopped + m_Shutdown.wait(&aTimeValue); } else { @@ -381,7 +461,9 @@ PresenterClockTimer::PresenterClockTimer (const Reference<XComponentContext>& rx mnTimerTaskId(PresenterTimer::NotAValidTaskId), mbIsCallbackPending(false), mxRequestCallback() + , m_xContext(rxContext) { + assert(m_xContext.is()); Reference<lang::XMultiComponentFactory> xFactory ( rxContext->getServiceManager(), UNO_QUERY); if (xFactory.is()) @@ -416,6 +498,7 @@ void PresenterClockTimer::AddListener (const SharedListener& rListener) if (mnTimerTaskId==PresenterTimer::NotAValidTaskId) { mnTimerTaskId = PresenterTimer::ScheduleRepeatedTask( + m_xContext, [this] (TimeValue const& rTime) { return this->CheckCurrentTime(rTime); }, 0, 250000000 /*ns*/); diff --git a/sdext/source/presenter/PresenterTimer.hxx b/sdext/source/presenter/PresenterTimer.hxx index 6b6ce0eef029..48784970b2a8 100644 --- a/sdext/source/presenter/PresenterTimer.hxx +++ b/sdext/source/presenter/PresenterTimer.hxx @@ -57,6 +57,7 @@ public: nIntervall ns long until CancelTask is called. */ static sal_Int32 ScheduleRepeatedTask ( + const css::uno::Reference<css::uno::XComponentContext>& xContext, const Task& rTask, const sal_Int64 nFirst, const sal_Int64 nIntervall); @@ -108,6 +109,7 @@ private: sal_Int32 mnTimerTaskId; bool mbIsCallbackPending; css::uno::Reference<css::awt::XRequestCallback> mxRequestCallback; + const css::uno::Reference<css::uno::XComponentContext> m_xContext; PresenterClockTimer ( const css::uno::Reference<css::uno::XComponentContext>& rxContext); |