Add a class that runs a callback after a (resettable) timeout. This will be used later for unmounting after a certain idle time
This commit is contained in:
parent
938528840b
commit
4dab8c7426
1
src/cli/CallAfterTimeout.cpp
Normal file
1
src/cli/CallAfterTimeout.cpp
Normal file
@ -0,0 +1 @@
|
||||
#include "CallAfterTimeout.h"
|
57
src/cli/CallAfterTimeout.h
Normal file
57
src/cli/CallAfterTimeout.h
Normal file
@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
#ifndef MESSMER_CRYFS_SRC_CLI_CALLAFTERTIMEOUT_H
|
||||
#define MESSMER_CRYFS_SRC_CLI_CALLAFTERTIMEOUT_H
|
||||
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <messmer/cpp-utils/thread/LoopThread.h>
|
||||
|
||||
namespace cryfs {
|
||||
class CallAfterTimeout final {
|
||||
public:
|
||||
CallAfterTimeout(boost::chrono::milliseconds timeout, std::function<void()> callback);
|
||||
void resetTimer();
|
||||
private:
|
||||
bool _checkTimeoutThreadIteration();
|
||||
boost::chrono::time_point<boost::chrono::steady_clock> _targetTime();
|
||||
bool _callCallbackIfTimeout();
|
||||
|
||||
std::function<void()> _callback;
|
||||
boost::chrono::milliseconds _timeout;
|
||||
boost::chrono::time_point<boost::chrono::steady_clock> _start;
|
||||
cpputils::LoopThread _checkTimeoutThread;
|
||||
std::mutex _mutex;
|
||||
};
|
||||
|
||||
inline CallAfterTimeout::CallAfterTimeout(boost::chrono::milliseconds timeout, std::function<void()> callback)
|
||||
:_callback(callback), _timeout(timeout), _start(), _checkTimeoutThread(std::bind(&CallAfterTimeout::_checkTimeoutThreadIteration, this)) {
|
||||
resetTimer();
|
||||
_checkTimeoutThread.start();
|
||||
}
|
||||
|
||||
inline void CallAfterTimeout::resetTimer() {
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
_start = boost::chrono::steady_clock::now();
|
||||
}
|
||||
|
||||
inline bool CallAfterTimeout::_checkTimeoutThreadIteration() {
|
||||
boost::this_thread::sleep_until(_targetTime());
|
||||
return _callCallbackIfTimeout();
|
||||
}
|
||||
|
||||
inline boost::chrono::time_point<boost::chrono::steady_clock> CallAfterTimeout::_targetTime() {
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
return _start + _timeout;
|
||||
}
|
||||
|
||||
inline bool CallAfterTimeout::_callCallbackIfTimeout() {
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
if (boost::chrono::steady_clock::now() >= _start + _timeout) {
|
||||
_callback();
|
||||
return false; // Stop thread
|
||||
}
|
||||
return true; // Continue thread
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
67
test/cli/CallAfterTimeoutTest.cpp
Normal file
67
test/cli/CallAfterTimeoutTest.cpp
Normal file
@ -0,0 +1,67 @@
|
||||
#include <google/gtest/gtest.h>
|
||||
#include <messmer/cpp-utils/pointer/unique_ref.h>
|
||||
#include "../../src/cli/CallAfterTimeout.h"
|
||||
|
||||
using cpputils::unique_ref;
|
||||
using cpputils::make_unique_ref;
|
||||
using boost::chrono::milliseconds;
|
||||
using boost::chrono::minutes;
|
||||
using boost::chrono::duration_cast;
|
||||
using boost::this_thread::sleep_for;
|
||||
using namespace cryfs;
|
||||
|
||||
class CallAfterTimeoutTest : public ::testing::Test {
|
||||
public:
|
||||
unique_ref<CallAfterTimeout> callAfterTimeout(milliseconds timeout) {
|
||||
return make_unique_ref<CallAfterTimeout>(timeout, [this] {called = true;});
|
||||
}
|
||||
|
||||
bool called = false;
|
||||
};
|
||||
|
||||
TEST_F(CallAfterTimeoutTest, NoReset_1) {
|
||||
auto obj = callAfterTimeout(milliseconds(50));
|
||||
sleep_for(milliseconds(40));
|
||||
EXPECT_FALSE(called);
|
||||
sleep_for(milliseconds(20));
|
||||
EXPECT_TRUE(called);
|
||||
}
|
||||
|
||||
TEST_F(CallAfterTimeoutTest, NoReset_2) {
|
||||
auto obj = callAfterTimeout(milliseconds(100));
|
||||
sleep_for(milliseconds(90));
|
||||
EXPECT_FALSE(called);
|
||||
sleep_for(milliseconds(20));
|
||||
EXPECT_TRUE(called);
|
||||
}
|
||||
|
||||
TEST_F(CallAfterTimeoutTest, DoesntCallTwice) {
|
||||
auto obj = callAfterTimeout(milliseconds(50));
|
||||
sleep_for(milliseconds(60));
|
||||
EXPECT_TRUE(called);
|
||||
called = false;
|
||||
sleep_for(milliseconds(60));
|
||||
EXPECT_FALSE(called);
|
||||
}
|
||||
|
||||
TEST_F(CallAfterTimeoutTest, OneReset) {
|
||||
auto obj = callAfterTimeout(milliseconds(50));
|
||||
sleep_for(milliseconds(40));
|
||||
obj->resetTimer();
|
||||
sleep_for(milliseconds(40));
|
||||
EXPECT_FALSE(called);
|
||||
sleep_for(milliseconds(20));
|
||||
EXPECT_TRUE(called);
|
||||
}
|
||||
|
||||
TEST_F(CallAfterTimeoutTest, TwoResets) {
|
||||
auto obj = callAfterTimeout(milliseconds(50));
|
||||
sleep_for(milliseconds(20));
|
||||
obj->resetTimer();
|
||||
sleep_for(milliseconds(40));
|
||||
obj->resetTimer();
|
||||
sleep_for(milliseconds(40));
|
||||
EXPECT_FALSE(called);
|
||||
sleep_for(milliseconds(20));
|
||||
EXPECT_TRUE(called);
|
||||
}
|
Loading…
Reference in New Issue
Block a user