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