WakeupThread - re-factor to have a single shared wakeup thread.
The WakeupThread is an attempt to avoid needing to call gettimeofday and/or update a visual status bar very regularly, and to have a thread marking the passing of time to emit progress updates infrequently. Re-factor this to have a single time-keeping thread, so it will be easier to shutdown and re-start for LOK; and also to simplify some of the complexity lurking here. Change-Id: Ia95890e5d6041a029484aa3f7df13b59a0397086 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167949 Reviewed-by: Michael Meeks <michael.meeks@collabora.com> Tested-by: Jenkins
This commit is contained in:
@@ -150,7 +150,7 @@ class StatusIndicatorFactory final : public ::cppu::WeakImplHelper<
|
||||
|
||||
/** Notify us if a fix time is over. We use it to implement an
|
||||
intelligent "Reschedule" ... */
|
||||
rtl::Reference<WakeUpThread> m_pWakeUp;
|
||||
std::unique_ptr<WakeUpThread> m_pWakeUp;
|
||||
|
||||
/** Our WakeUpThread calls us in our interface method "XUpdatable::update().
|
||||
There we set this member m_bAllowReschedule to sal_True. Next time if our impl_reschedule()
|
||||
|
||||
@@ -23,9 +23,6 @@
|
||||
|
||||
#include <com/sun/star/uno/Reference.hxx>
|
||||
#include <cppuhelper/weakref.hxx>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <salhelper/thread.hxx>
|
||||
|
||||
namespace com::sun::star::util
|
||||
{
|
||||
@@ -34,19 +31,17 @@ class XUpdatable;
|
||||
|
||||
namespace framework
|
||||
{
|
||||
class WakeUpThread final : public salhelper::Thread
|
||||
/// Provides a regular callback to @updatable roughly every 25ms while running
|
||||
class WakeUpThread final
|
||||
{
|
||||
css::uno::WeakReference<css::util::XUpdatable> updatable_;
|
||||
std::condition_variable condition_;
|
||||
std::mutex mutex_;
|
||||
bool terminate_;
|
||||
|
||||
void execute() override;
|
||||
css::uno::Reference<css::util::XUpdatable> _updatable;
|
||||
|
||||
public:
|
||||
WakeUpThread(css::uno::Reference<css::util::XUpdatable> const& updatable);
|
||||
|
||||
void stop();
|
||||
|
||||
static void joinThread();
|
||||
static void startThread();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -544,24 +544,19 @@ void StatusIndicatorFactory::impl_startWakeUpThread()
|
||||
if (m_bDisableReschedule)
|
||||
return;
|
||||
|
||||
if (!m_pWakeUp.is())
|
||||
{
|
||||
m_pWakeUp = new WakeUpThread(this);
|
||||
m_pWakeUp->launch();
|
||||
}
|
||||
if (!m_pWakeUp)
|
||||
m_pWakeUp.reset(new WakeUpThread(this));
|
||||
}
|
||||
|
||||
void StatusIndicatorFactory::impl_stopWakeUpThread()
|
||||
{
|
||||
rtl::Reference<WakeUpThread> wakeUp;
|
||||
std::unique_ptr<WakeUpThread> wakeUp;
|
||||
{
|
||||
std::scoped_lock g(m_mutex);
|
||||
std::swap(wakeUp, m_pWakeUp);
|
||||
}
|
||||
if (wakeUp.is())
|
||||
{
|
||||
if (wakeUp)
|
||||
wakeUp->stop();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace framework
|
||||
|
||||
@@ -21,40 +21,154 @@
|
||||
|
||||
#include <com/sun/star/uno/Reference.hxx>
|
||||
#include <com/sun/star/util/XUpdatable.hpp>
|
||||
#include <rtl/ref.hxx>
|
||||
#include <osl/thread.hxx>
|
||||
#include <salhelper/thread.hxx>
|
||||
#include <condition_variable>
|
||||
#include <chrono>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
|
||||
#include <helper/wakeupthread.hxx>
|
||||
#include <chrono>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
void framework::WakeUpThread::execute() {
|
||||
for (;;) {
|
||||
/// We only need one thread to wake everyone up.
|
||||
|
||||
namespace
|
||||
{
|
||||
class SharedWakeUpThread final : public salhelper::Thread
|
||||
{
|
||||
static std::vector<css::uno::WeakReference<css::util::XUpdatable>> updatables;
|
||||
std::condition_variable condition;
|
||||
bool terminate;
|
||||
|
||||
public:
|
||||
static rtl::Reference<SharedWakeUpThread> wakeupThread;
|
||||
|
||||
static std::mutex& getMutex()
|
||||
{
|
||||
static std::mutex mutex;
|
||||
return mutex;
|
||||
}
|
||||
|
||||
SharedWakeUpThread()
|
||||
: Thread("WakeUpThread")
|
||||
, terminate(false)
|
||||
{
|
||||
assert(!wakeupThread);
|
||||
launch();
|
||||
}
|
||||
|
||||
void execute() override
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
std::unique_lock g(mutex_);
|
||||
condition_.wait_for(g, 25ms, [this] { return terminate_; });
|
||||
if (terminate_) {
|
||||
std::unique_lock g(getMutex());
|
||||
condition.wait_for(g, 25ms, [this] { return terminate; });
|
||||
if (terminate || updatables.empty())
|
||||
break;
|
||||
|
||||
auto copyOfUpdatables = updatables;
|
||||
g.unlock();
|
||||
|
||||
for (auto& it : copyOfUpdatables)
|
||||
{
|
||||
css::uno::Reference<css::util::XUpdatable> up(it);
|
||||
if (up.is()) // check weak
|
||||
up->update();
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_lock g(getMutex());
|
||||
if (updatables.empty())
|
||||
{
|
||||
terminate = false;
|
||||
wakeupThread.clear();
|
||||
}
|
||||
}
|
||||
|
||||
static void startThread()
|
||||
{
|
||||
std::unique_lock g(getMutex());
|
||||
if (!updatables.empty() && !wakeupThread)
|
||||
wakeupThread = new SharedWakeUpThread();
|
||||
}
|
||||
|
||||
void stopWithLock(std::unique_lock<std::mutex>& g)
|
||||
{
|
||||
terminate = true;
|
||||
condition.notify_one();
|
||||
g.unlock();
|
||||
|
||||
join();
|
||||
}
|
||||
|
||||
static void disposeThreadWithLock(std::unique_lock<std::mutex>& g)
|
||||
{
|
||||
if (wakeupThread)
|
||||
{
|
||||
auto holdRef = wakeupThread;
|
||||
wakeupThread.clear();
|
||||
holdRef->stopWithLock(g);
|
||||
}
|
||||
assert(!wakeupThread);
|
||||
}
|
||||
|
||||
static void add(css::uno::WeakReference<css::util::XUpdatable> up)
|
||||
{
|
||||
std::unique_lock g(getMutex());
|
||||
updatables.push_back(up);
|
||||
if (!wakeupThread)
|
||||
wakeupThread = new SharedWakeUpThread();
|
||||
}
|
||||
|
||||
static void remove(css::uno::WeakReference<css::util::XUpdatable> up)
|
||||
{
|
||||
std::unique_lock g(getMutex());
|
||||
auto it = updatables.begin();
|
||||
bool found = false;
|
||||
for (; it != updatables.end(); ++it)
|
||||
{
|
||||
css::uno::Reference<css::util::XUpdatable> itValid(*it);
|
||||
if (!itValid || *it == up)
|
||||
{
|
||||
it = updatables.erase(it);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
css::uno::Reference<css::util::XUpdatable> up(updatable_);
|
||||
if (up.is()) {
|
||||
up->update();
|
||||
}
|
||||
(void)found; assert(found);
|
||||
if (updatables.empty())
|
||||
disposeThreadWithLock(g);
|
||||
}
|
||||
}
|
||||
|
||||
framework::WakeUpThread::WakeUpThread(
|
||||
css::uno::Reference<css::util::XUpdatable> const & updatable):
|
||||
Thread("WakeUpThread"), updatable_(updatable), terminate_(false)
|
||||
{}
|
||||
|
||||
void framework::WakeUpThread::stop() {
|
||||
static void joinThread()
|
||||
{
|
||||
std::unique_lock g(mutex_);
|
||||
terminate_ = true;
|
||||
std::unique_lock g(getMutex());
|
||||
disposeThreadWithLock(g);
|
||||
}
|
||||
condition_.notify_one();
|
||||
join();
|
||||
};
|
||||
|
||||
rtl::Reference<SharedWakeUpThread> SharedWakeUpThread::wakeupThread;
|
||||
std::vector<css::uno::WeakReference<css::util::XUpdatable>> SharedWakeUpThread::updatables;
|
||||
}
|
||||
|
||||
namespace framework
|
||||
{
|
||||
/* static */ void WakeUpThread::startThread() { SharedWakeUpThread::startThread(); }
|
||||
|
||||
WakeUpThread::WakeUpThread(css::uno::Reference<css::util::XUpdatable> const& up)
|
||||
: _updatable(up)
|
||||
{
|
||||
assert(_updatable);
|
||||
SharedWakeUpThread::add(_updatable);
|
||||
}
|
||||
|
||||
void WakeUpThread::stop() { SharedWakeUpThread::remove(_updatable); }
|
||||
|
||||
/* static */ void WakeUpThread::joinThread() { SharedWakeUpThread::joinThread(); }
|
||||
|
||||
} // namespace framework
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
||||
|
||||
Reference in New Issue
Block a user