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:
Sebastian Messmer 2015-11-12 13:08:43 -08:00
parent 938528840b
commit 4dab8c7426
3 changed files with 125 additions and 0 deletions

View File

@ -0,0 +1 @@
#include "CallAfterTimeout.h"

View 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

View 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);
}