Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
459 additions
and
128 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
#include "call_every_handler.h" | ||
|
||
namespace dronecore { | ||
|
||
CallEveryHandler::CallEveryHandler() | ||
{ | ||
} | ||
|
||
CallEveryHandler::~CallEveryHandler() | ||
{ | ||
} | ||
|
||
void CallEveryHandler::add(std::function<void()> callback, float interval_s, void **cookie) | ||
{ | ||
auto new_entry = std::make_shared<Entry>(); | ||
new_entry->callback = callback; | ||
new_entry->last_time = steady_time(); | ||
new_entry->interval_s = interval_s; | ||
|
||
void *new_cookie = static_cast<void *>(new_entry.get()); | ||
|
||
{ | ||
std::lock_guard<std::mutex> lock(_entries_mutex); | ||
_entries.insert(std::pair<void *, std::shared_ptr<Entry>>(new_cookie, new_entry)); | ||
} | ||
|
||
if (cookie != nullptr) { | ||
*cookie = new_cookie; | ||
} | ||
} | ||
|
||
void CallEveryHandler::change(float interval_s, const void *cookie) | ||
{ | ||
std::lock_guard<std::mutex> lock(_entries_mutex); | ||
|
||
auto it = _entries.find(const_cast<void *>(cookie)); | ||
if (it != _entries.end()) { | ||
it->second->interval_s = interval_s; | ||
} | ||
} | ||
|
||
void CallEveryHandler::reset(const void *cookie) | ||
{ | ||
std::lock_guard<std::mutex> lock(_entries_mutex); | ||
|
||
auto it = _entries.find(const_cast<void *>(cookie)); | ||
if (it != _entries.end()) { | ||
it->second->last_time = steady_time(); | ||
} | ||
} | ||
|
||
void CallEveryHandler::remove(const void *cookie) | ||
{ | ||
std::lock_guard<std::mutex> lock(_entries_mutex); | ||
|
||
auto it = _entries.find(const_cast<void *>(cookie)); | ||
if (it != _entries.end()) { | ||
_entries.erase(const_cast<void *>(cookie)); | ||
} | ||
} | ||
|
||
void CallEveryHandler::run_once() | ||
{ | ||
_entries_mutex.lock(); | ||
|
||
for (auto it = _entries.begin(); it != _entries.end(); ++it) { | ||
|
||
if (elapsed_since_s(it->second->last_time) > double(it->second->interval_s)) { | ||
|
||
shift_steady_time_by(it->second->last_time, double(it->second->interval_s)); | ||
|
||
if (it->second->callback) { | ||
|
||
// Get a copy for the callback because we unlock. | ||
std::function<void()> callback = it->second->callback; | ||
|
||
// Unlock while we callback because it might in turn want to add timeouts. | ||
_entries_mutex.unlock(); | ||
callback(); | ||
_entries_mutex.lock(); | ||
} | ||
} | ||
} | ||
_entries_mutex.unlock(); | ||
} | ||
|
||
} // namespace dronecore |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
#pragma once | ||
|
||
#include <mutex> | ||
#include <memory> | ||
#include <functional> | ||
#include <map> | ||
#include "global_include.h" | ||
|
||
namespace dronecore { | ||
|
||
class CallEveryHandler | ||
{ | ||
public: | ||
CallEveryHandler(); | ||
~CallEveryHandler(); | ||
|
||
// delete copy and move constructors and assign operators | ||
CallEveryHandler(CallEveryHandler const &) = delete; // Copy construct | ||
CallEveryHandler(CallEveryHandler &&) = delete; // Move construct | ||
CallEveryHandler &operator=(CallEveryHandler const &) = delete; // Copy assign | ||
CallEveryHandler &operator=(CallEveryHandler &&) = delete; // Move assign | ||
|
||
void add(std::function<void()> callback, float interval_s, void **cookie); | ||
void change(float interval_s, const void *cookie); | ||
void reset(const void *cookie); | ||
void remove(const void *cookie); | ||
|
||
void run_once(); | ||
|
||
private: | ||
struct Entry { | ||
std::function<void()> callback; | ||
dl_time_t last_time; | ||
float interval_s; | ||
}; | ||
|
||
std::map<void *, std::shared_ptr<Entry>> _entries {}; | ||
std::mutex _entries_mutex {}; | ||
}; | ||
|
||
} // namespace dronecore |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
#include "call_every_handler.h" | ||
#include <gtest/gtest.h> | ||
#include <atomic> | ||
#include "log.h" | ||
|
||
using namespace dronecore; | ||
|
||
TEST(CallEveryHandler, Single) | ||
{ | ||
CallEveryHandler ceh; | ||
|
||
int num_called = 0; | ||
|
||
void *cookie = nullptr; | ||
ceh.add([&num_called]() { ++num_called; }, 0.1f, &cookie); | ||
|
||
for (int i = 0; i < 11; ++i) { | ||
std::this_thread::sleep_for(std::chrono::milliseconds(10)); | ||
ceh.run_once(); | ||
} | ||
EXPECT_EQ(num_called, 1); | ||
|
||
UNUSED(cookie); | ||
} | ||
|
||
TEST(CallEveryHandler, Multiple) | ||
{ | ||
CallEveryHandler ceh; | ||
|
||
int num_called = 0; | ||
|
||
void *cookie = nullptr; | ||
ceh.add([&num_called]() { ++num_called; }, 0.1f, &cookie); | ||
|
||
for (int i = 0; i < 10; ++i) { | ||
std::this_thread::sleep_for(std::chrono::milliseconds(100)); | ||
ceh.run_once(); | ||
} | ||
EXPECT_EQ(num_called, 10); | ||
|
||
num_called = 0; | ||
ceh.change(0.2f, cookie); | ||
|
||
for (int i = 0; i < 20; ++i) { | ||
std::this_thread::sleep_for(std::chrono::milliseconds(100)); | ||
ceh.run_once(); | ||
} | ||
|
||
EXPECT_EQ(num_called, 10); | ||
|
||
num_called = 0; | ||
ceh.remove(cookie); | ||
std::this_thread::sleep_for(std::chrono::milliseconds(100)); | ||
ceh.run_once(); | ||
EXPECT_EQ(num_called, 0); | ||
} | ||
|
||
TEST(CallEveryHandler, InParallel) | ||
{ | ||
CallEveryHandler ceh; | ||
|
||
int num_called1 = 0; | ||
int num_called2 = 0; | ||
|
||
void *cookie1 = nullptr; | ||
void *cookie2 = nullptr; | ||
ceh.add([&num_called1]() { ++num_called1; }, 0.1f, &cookie1); | ||
ceh.add([&num_called2]() { ++num_called2; }, 0.2f, &cookie2); | ||
|
||
for (int i = 0; i < 10; ++i) { | ||
std::this_thread::sleep_for(std::chrono::milliseconds(100)); | ||
ceh.run_once(); | ||
} | ||
|
||
EXPECT_EQ(num_called1, 10); | ||
EXPECT_EQ(num_called2, 5); | ||
|
||
num_called1 = 0; | ||
num_called2 = 0; | ||
|
||
ceh.change(0.4f, cookie1); | ||
ceh.change(0.1f, cookie2); | ||
|
||
for (int i = 0; i < 10; ++i) { | ||
std::this_thread::sleep_for(std::chrono::milliseconds(100)); | ||
ceh.run_once(); | ||
} | ||
|
||
EXPECT_EQ(num_called1, 2); | ||
EXPECT_EQ(num_called2, 10); | ||
} | ||
|
||
TEST(CallEveryHandler, Reset) | ||
{ | ||
CallEveryHandler ceh; | ||
|
||
int num_called = 0; | ||
|
||
void *cookie = nullptr; | ||
ceh.add([&num_called]() { ++num_called; }, 0.1f, &cookie); | ||
|
||
for (int i = 0; i < 8; ++i) { | ||
std::this_thread::sleep_for(std::chrono::milliseconds(10)); | ||
ceh.run_once(); | ||
if (i == 8) { | ||
} | ||
} | ||
EXPECT_EQ(num_called, 0); | ||
|
||
ceh.reset(cookie); | ||
|
||
for (int i = 0; i < 8; ++i) { | ||
std::this_thread::sleep_for(std::chrono::milliseconds(10)); | ||
ceh.run_once(); | ||
} | ||
EXPECT_EQ(num_called, 0); | ||
|
||
for (int i = 0; i < 3; ++i) { | ||
std::this_thread::sleep_for(std::chrono::milliseconds(10)); | ||
ceh.run_once(); | ||
} | ||
EXPECT_EQ(num_called, 1); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.