utility/timer: Make movable
Now that we can update the callbacks of our sources, we can move the
timer object freely by updating the callback when moved.
Tested:
Unit tests pass, and we no longer see any valgrind issues when
moving the timer object.
Change-Id: I15baf97538459ca8b9c48b75dba77d09b7b5075b
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/src/sdeventplus/utility/timer.cpp b/src/sdeventplus/utility/timer.cpp
index 979c0af..2f28257 100644
--- a/src/sdeventplus/utility/timer.cpp
+++ b/src/sdeventplus/utility/timer.cpp
@@ -2,6 +2,7 @@
#include <sdeventplus/clock.hpp>
#include <sdeventplus/utility/timer.hpp>
#include <stdexcept>
+#include <utility>
namespace sdeventplus
{
@@ -9,6 +10,36 @@
{
template <ClockId Id>
+Timer<Id>::Timer(Timer&& other) :
+ expired(std::move(other.expired)),
+ initialized(std::move(other.initialized)),
+ callback(std::move(other.callback)), clock(std::move(other.clock)),
+ interval(std::move(other.interval)), timeSource(std::move(other.timeSource))
+{
+ timeSource.set_callback(std::bind(&Timer::internalCallback, this,
+ std::placeholders::_1,
+ std::placeholders::_2));
+}
+
+template <ClockId Id>
+Timer<Id>& Timer<Id>::operator=(Timer&& other)
+{
+ if (this != &other)
+ {
+ expired = std::move(other.expired);
+ initialized = std::move(other.initialized);
+ callback = std::move(other.callback);
+ clock = std::move(other.clock);
+ interval = std::move(other.interval);
+ timeSource = std::move(other.timeSource);
+ timeSource.set_callback(std::bind(&Timer::internalCallback, this,
+ std::placeholders::_1,
+ std::placeholders::_2));
+ }
+ return *this;
+}
+
+template <ClockId Id>
Timer<Id>::Timer(const Event& event, Callback&& callback,
std::optional<Duration> interval,
typename source::Time<Id>::Accuracy accuracy) :
diff --git a/src/sdeventplus/utility/timer.hpp b/src/sdeventplus/utility/timer.hpp
index f5d4766..e45cf46 100644
--- a/src/sdeventplus/utility/timer.hpp
+++ b/src/sdeventplus/utility/timer.hpp
@@ -38,9 +38,9 @@
using Callback = std::function<void(Timer<Id>&)>;
Timer(const Timer& other) = delete;
- Timer(Timer&& other) = default;
+ Timer(Timer&& other);
Timer& operator=(const Timer& other) = delete;
- Timer& operator=(Timer&& other) = default;
+ Timer& operator=(Timer&& other);
virtual ~Timer() = default;
/** @brief Creates a new timer on the given event loop.
diff --git a/test/utility/timer.cpp b/test/utility/timer.cpp
index 6d5dff0..6c04e87 100644
--- a/test/utility/timer.cpp
+++ b/test/utility/timer.cpp
@@ -47,8 +47,11 @@
sd_event* const expected_event = reinterpret_cast<sd_event*>(1234);
sd_event_source* const expected_source =
reinterpret_cast<sd_event_source*>(2345);
+ sd_event_source* const expected_source2 =
+ reinterpret_cast<sd_event_source*>(3456);
const milliseconds interval{134};
const milliseconds starting_time{10};
+ const milliseconds starting_time2{30};
sd_event_time_handler_t handler = nullptr;
void* handler_userdata;
std::unique_ptr<Event> event;
@@ -340,6 +343,44 @@
EXPECT_THROW(timer->setEnabled(true), std::runtime_error);
}
+TEST_F(TimerTest, CallbackMove)
+{
+ size_t called = 0;
+ callback = [&]() { ++called; };
+
+ expectNow(starting_time2);
+ EXPECT_CALL(mock,
+ sd_event_source_set_userdata(expected_source2, testing::_))
+ .WillOnce(Return(nullptr));
+ EXPECT_CALL(mock, sd_event_add_time(expected_event, testing::_,
+ static_cast<clockid_t>(testClock),
+ microseconds(starting_time2).count(),
+ 1000, testing::_, nullptr))
+ .WillOnce(DoAll(SetArgPointee<1>(expected_source2), Return(0)));
+ EXPECT_CALL(mock, sd_event_source_unref(expected_source2))
+ .WillOnce(Return(nullptr));
+ EXPECT_CALL(mock,
+ sd_event_source_set_enabled(
+ expected_source2, static_cast<int>(source::Enabled::Off)))
+ .WillOnce(Return(0))
+ .WillOnce(Return(0));
+ TestTimer local_timer(*event, nullptr);
+
+ // Move assign
+ local_timer = std::move(*timer);
+ timer.reset();
+
+ // Move construct
+ timer = std::make_unique<TestTimer>(std::move(local_timer));
+
+ // handler_userdata should have been updated and the callback should work
+ const milliseconds new_time(90);
+ expectNow(new_time);
+ expectSetTime(new_time + interval);
+ EXPECT_EQ(0, handler(nullptr, 0, handler_userdata));
+ EXPECT_EQ(1, called);
+}
+
TEST_F(TimerTest, SetValuesExpiredTimer)
{
const milliseconds new_time(90);