summaryrefslogtreecommitdiff
path: root/sdext
diff options
context:
space:
mode:
authorMichael Stahl <mstahl@redhat.com>2017-05-24 16:14:56 +0200
committerAndras Timar <andras.timar@collabora.com>2017-05-30 09:41:22 +0200
commit356e3ab9945e36fae7a07bb1c4948df5686236cf (patch)
treecb84f66a4d947dc52c1f0e3c2494bc2b690a5323 /sdext
parentb6218e94f0bf546ac065be3f874ccd47c9381c78 (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.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.cxx99
-rw-r--r--sdext/source/presenter/PresenterTimer.hxx2
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);