summaryrefslogtreecommitdiff
path: root/sdext
diff options
context:
space:
mode:
authorMichael Stahl <mstahl@redhat.com>2017-05-24 16:14:56 +0200
committerMichael Stahl <mstahl@redhat.com>2017-05-30 12:50:19 +0200
commit07df9ec05b1fa0c5a0a0c3d70c87917d37607155 (patch)
tree58c2d9fb0061e43549f9c28b816855a56c11e42d /sdext
parentc3c208e1fdfd60b95fc09ed48d9ee975bddb214d (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/38203 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Michael Stahl <mstahl@redhat.com>
Diffstat (limited to 'sdext')
-rw-r--r--sdext/source/presenter/PresenterScrollBar.cxx1
-rw-r--r--sdext/source/presenter/PresenterScrollBar.hxx3
-rw-r--r--sdext/source/presenter/PresenterTextView.cxx6
-rw-r--r--sdext/source/presenter/PresenterTextView.hxx2
-rw-r--r--sdext/source/presenter/PresenterTimer.cxx96
-rw-r--r--sdext/source/presenter/PresenterTimer.hxx2
6 files changed, 101 insertions, 9 deletions
diff --git a/sdext/source/presenter/PresenterScrollBar.cxx b/sdext/source/presenter/PresenterScrollBar.cxx
index 89ac7f52ce16..988b3d82d791 100644
--- a/sdext/source/presenter/PresenterScrollBar.cxx
+++ b/sdext/source/presenter/PresenterScrollBar.cxx
@@ -790,6 +790,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 46a6704bc7f8..70c670e7fb34 100644
--- a/sdext/source/presenter/PresenterScrollBar.hxx
+++ b/sdext/source/presenter/PresenterScrollBar.hxx
@@ -58,6 +58,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 3e4d174a21eb..ca48c6f15f4f 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)),
@@ -1068,9 +1069,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),
@@ -1091,6 +1094,7 @@ void PresenterTextCaret::ShowCaret()
if (mnCaretBlinkTaskId == 0)
{
mnCaretBlinkTaskId = PresenterTimer::ScheduleRepeatedTask (
+ m_xContext,
[this] (TimeValue const&) { return this->InvertCaret(); },
CaretBlinkInterval,
CaretBlinkInterval);
diff --git a/sdext/source/presenter/PresenterTextView.hxx b/sdext/source/presenter/PresenterTextView.hxx
index cca8b4a89ad1..5c990c64e89e 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 4c18c07a2c79..0fba43273613 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>
@@ -70,7 +75,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,
@@ -89,6 +95,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;
@@ -100,8 +109,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;
@@ -110,15 +121,39 @@ 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&) override
+ {
+ }
+
+ virtual void SAL_CALL queryTermination(lang::EventObject const&) override
+ {
+ }
+
+ virtual void SAL_CALL notifyTermination(lang::EventObject const&) 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 nInterval)
{
+ assert(xContext.is());
TimeValue aCurrentTime;
if (TimerScheduler::GetCurrentTime(aCurrentTime))
{
@@ -127,7 +162,7 @@ sal_Int32 PresenterTimer::ScheduleRepeatedTask (
aDueTime,
TimerScheduler::ConvertFromTimeValue (aCurrentTime) + nDelay);
SharedTimerTask pTask (TimerScheduler::CreateTimerTask(rTask, aDueTime, nInterval));
- TimerScheduler::Instance()->ScheduleTask(pTask);
+ TimerScheduler::Instance(xContext)->ScheduleTask(pTask);
return pTask->mnTaskId;
}
@@ -136,7 +171,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 ========================================================
@@ -145,23 +184,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()
@@ -221,6 +270,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");
@@ -268,7 +344,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
{
@@ -380,7 +457,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())
@@ -415,6 +494,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 739955d31c9a..d7d14450f38b 100644
--- a/sdext/source/presenter/PresenterTimer.hxx
+++ b/sdext/source/presenter/PresenterTimer.hxx
@@ -57,6 +57,7 @@ public:
nInterval 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 nInterval);
@@ -107,6 +108,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);