diff options
author | Henning Baldersheim <balder@yahoo-inc.com> | 2022-03-01 05:42:38 +0000 |
---|---|---|
committer | Henning Baldersheim <balder@yahoo-inc.com> | 2022-03-03 11:39:52 +0000 |
commit | 64c08801e0ac5094fb111c5fe3ea63cc7597506d (patch) | |
tree | a34f000d2743b864e22e322d9ce94b655c86ac97 /vespalib | |
parent | 6f78fdc9750ad3ac03b14166b6838c628487458c (diff) |
Let the InvocationService drive the clock instead of having its own ticking loop.
Also use sleep_until to get intervals indendant of invoke cost as long as cost is within interval.
This also also saves a clock sample and simplifies implementation.
Diffstat (limited to 'vespalib')
4 files changed, 35 insertions, 14 deletions
diff --git a/vespalib/src/tests/invokeservice/invokeservice_test.cpp b/vespalib/src/tests/invokeservice/invokeservice_test.cpp index 1d4791f4a33..d56eb28e6c7 100644 --- a/vespalib/src/tests/invokeservice/invokeservice_test.cpp +++ b/vespalib/src/tests/invokeservice/invokeservice_test.cpp @@ -29,6 +29,25 @@ TEST("require that wakeup is called") { EXPECT_EQUAL(countAtStop, a._count); } +TEST("require that now is moving forward") { + InvokeCounter a; + InvokeServiceImpl service(1ms); + EXPECT_EQUAL(0u, a._count); + steady_time prev = steady_clock::now(); + auto ra = service.registerInvoke([&prev, &a, now=service.nowPtr() ]() noexcept { + EXPECT_GREATER(now->load(), prev); + prev = now->load(); + a.inc(); + }); + EXPECT_TRUE(ra); + a.wait_for_atleast(100); + ra.reset(); + EXPECT_GREATER_EQUAL(a._count, 100u); + steady_time now = steady_clock::now(); + EXPECT_GREATER(now, prev); + EXPECT_LESS(now - prev, 5s); +} + TEST("require that same wakeup can be registered multiple times.") { InvokeCounter a; InvokeCounter b; diff --git a/vespalib/src/vespa/vespalib/util/invokeservice.h b/vespalib/src/vespa/vespalib/util/invokeservice.h index 3e3973234d1..22bee0d4526 100644 --- a/vespalib/src/vespa/vespalib/util/invokeservice.h +++ b/vespalib/src/vespa/vespalib/util/invokeservice.h @@ -3,6 +3,7 @@ #pragma once #include "idestructorcallback.h" +#include "time.h" #include <functional> namespace vespalib { @@ -13,8 +14,9 @@ namespace vespalib { **/ class InvokeService { public: + using InvokeFunc = std::function<void()>; virtual ~InvokeService() = default; - virtual std::unique_ptr<IDestructorCallback> registerInvoke(std::function<void()> func) = 0; + virtual std::unique_ptr<IDestructorCallback> registerInvoke(InvokeFunc func) = 0; }; } diff --git a/vespalib/src/vespa/vespalib/util/invokeserviceimpl.cpp b/vespalib/src/vespa/vespalib/util/invokeserviceimpl.cpp index ffa0825c950..eac84568ec2 100644 --- a/vespalib/src/vespa/vespalib/util/invokeserviceimpl.cpp +++ b/vespalib/src/vespa/vespalib/util/invokeserviceimpl.cpp @@ -7,11 +7,12 @@ namespace vespalib { InvokeServiceImpl::InvokeServiceImpl(duration napTime) : _naptime(napTime), + _now(steady_clock::now()), _lock(), _currId(0), _closed(false), _toInvoke(), - _thread() + _thread(std::make_unique<std::thread>([this]() { runLoop(); })) { } @@ -22,9 +23,7 @@ InvokeServiceImpl::~InvokeServiceImpl() assert(_toInvoke.empty()); _closed = true; } - if (_thread) { - _thread->join(); - } + _thread->join(); } class InvokeServiceImpl::Registration : public IDestructorCallback { @@ -44,20 +43,17 @@ private: }; std::unique_ptr<IDestructorCallback> -InvokeServiceImpl::registerInvoke(VoidFunc func) { +InvokeServiceImpl::registerInvoke(InvokeFunc func) { std::lock_guard guard(_lock); uint64_t id = _currId++; _toInvoke.emplace_back(id, std::move(func)); - if ( ! _thread) { - _thread = std::make_unique<std::thread>([this]() { runLoop(); }); - } return std::make_unique<Registration>(this, id); } void InvokeServiceImpl::unregister(uint64_t id) { std::lock_guard guard(_lock); - auto found = std::find_if(_toInvoke.begin(), _toInvoke.end(), [id](const std::pair<uint64_t, VoidFunc> & a) { + auto found = std::find_if(_toInvoke.begin(), _toInvoke.end(), [id](const IdAndFunc & a) { return id == a.first; }); assert (found != _toInvoke.end()); @@ -68,6 +64,8 @@ void InvokeServiceImpl::runLoop() { bool done = false; while ( ! done ) { + const steady_time now = steady_clock::now(); + _now.store(now, std::memory_order_relaxed); { std::lock_guard guard(_lock); for (auto & func: _toInvoke) { @@ -76,7 +74,7 @@ InvokeServiceImpl::runLoop() { done = _closed; } if ( ! done) { - std::this_thread::sleep_for(_naptime); + std::this_thread::sleep_until(now + _naptime); } } diff --git a/vespalib/src/vespa/vespalib/util/invokeserviceimpl.h b/vespalib/src/vespa/vespalib/util/invokeserviceimpl.h index 3b0c7690731..2448e381610 100644 --- a/vespalib/src/vespa/vespalib/util/invokeserviceimpl.h +++ b/vespalib/src/vespa/vespalib/util/invokeserviceimpl.h @@ -14,22 +14,24 @@ namespace vespalib { * An invoke service what will invoke the given function with at specified frequency. */ class InvokeServiceImpl : public InvokeService { - using VoidFunc = std::function<void()>; public: InvokeServiceImpl(duration napTime); InvokeServiceImpl(const InvokeServiceImpl &) = delete; InvokeServiceImpl & operator=(const InvokeServiceImpl &) = delete; ~InvokeServiceImpl() override; - std::unique_ptr<IDestructorCallback> registerInvoke(VoidFunc func) override; + std::unique_ptr<IDestructorCallback> registerInvoke(InvokeFunc func) override; + const std::atomic<steady_time> * nowPtr() const { return &_now; } private: + using IdAndFunc = std::pair<uint64_t, InvokeFunc>; class Registration; void unregister(uint64_t id); void runLoop(); duration _naptime; + std::atomic<steady_time> _now; std::mutex _lock; uint64_t _currId; bool _closed; - std::vector<std::pair<uint64_t, VoidFunc>> _toInvoke; + std::vector<IdAndFunc> _toInvoke; std::unique_ptr<std::thread> _thread; }; |