summaryrefslogtreecommitdiffstats
path: root/vespalib
diff options
context:
space:
mode:
authorHenning Baldersheim <balder@yahoo-inc.com>2022-03-01 05:42:38 +0000
committerHenning Baldersheim <balder@yahoo-inc.com>2022-03-03 11:39:52 +0000
commit64c08801e0ac5094fb111c5fe3ea63cc7597506d (patch)
treea34f000d2743b864e22e322d9ce94b655c86ac97 /vespalib
parent6f78fdc9750ad3ac03b14166b6838c628487458c (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')
-rw-r--r--vespalib/src/tests/invokeservice/invokeservice_test.cpp19
-rw-r--r--vespalib/src/vespa/vespalib/util/invokeservice.h4
-rw-r--r--vespalib/src/vespa/vespalib/util/invokeserviceimpl.cpp18
-rw-r--r--vespalib/src/vespa/vespalib/util/invokeserviceimpl.h8
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;
};