clock: Add class for future use
diff --git a/.gitignore b/.gitignore
index c62c609..884d17b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,6 +42,7 @@
# Output binaries
/example/follow
+/test/clock
/test/event
/test/exception
/test/internal_sdref
diff --git a/src/Makefile.am b/src/Makefile.am
index 2943a2c..a027d5f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -4,6 +4,9 @@
libsdeventplus_la_SOURCES =
libsdeventplus_la_LIBADD = $(COMMON_LIBS)
+nobase_include_HEADERS += sdeventplus/clock.hpp
+libsdeventplus_la_SOURCES += sdeventplus/clock.cpp
+
nobase_include_HEADERS += sdeventplus/event.hpp
libsdeventplus_la_SOURCES += sdeventplus/event.cpp
@@ -16,6 +19,8 @@
nobase_include_HEADERS += sdeventplus/internal/sdref.hpp
libsdeventplus_la_SOURCES += sdeventplus/internal/sdref.cpp
+nobase_include_HEADERS += sdeventplus/internal/utils.hpp
+
nobase_include_HEADERS += sdeventplus/source/base.hpp
libsdeventplus_la_SOURCES += sdeventplus/source/base.cpp
diff --git a/src/sdeventplus/clock.cpp b/src/sdeventplus/clock.cpp
new file mode 100644
index 0000000..37395c4
--- /dev/null
+++ b/src/sdeventplus/clock.cpp
@@ -0,0 +1,38 @@
+#include <sdeventplus/clock.hpp>
+#include <sdeventplus/exception.hpp>
+#include <sdeventplus/internal/utils.hpp>
+#include <utility>
+
+namespace sdeventplus
+{
+
+template <ClockId Id>
+Clock<Id>::Clock(const Event& event) : event(event)
+{
+}
+
+template <ClockId Id>
+Clock<Id>::Clock(Event&& event) : event(std::move(event))
+{
+}
+
+template <ClockId Id>
+typename Clock<Id>::time_point Clock<Id>::now() const
+{
+ uint64_t now;
+ int r = event.getSdEvent()->sd_event_now(event.get(),
+ static_cast<clockid_t>(Id), &now);
+ if (r < 0)
+ {
+ throw SdEventError(-r, "sd_event_now");
+ }
+ return time_point(SdEventDuration(now));
+}
+
+template class Clock<ClockId::RealTime>;
+template class Clock<ClockId::Monotonic>;
+template class Clock<ClockId::BootTime>;
+template class Clock<ClockId::RealTimeAlarm>;
+template class Clock<ClockId::BootTimeAlarm>;
+
+} // namespace sdeventplus
diff --git a/src/sdeventplus/clock.hpp b/src/sdeventplus/clock.hpp
new file mode 100644
index 0000000..c59d721
--- /dev/null
+++ b/src/sdeventplus/clock.hpp
@@ -0,0 +1,41 @@
+#pragma once
+
+#include <chrono>
+#include <cstdint>
+#include <ctime>
+#include <sdeventplus/event.hpp>
+#include <sdeventplus/internal/utils.hpp>
+#include <type_traits>
+
+namespace sdeventplus
+{
+
+enum class ClockId : clockid_t
+{
+ RealTime = CLOCK_REALTIME,
+ Monotonic = CLOCK_MONOTONIC,
+ BootTime = CLOCK_BOOTTIME,
+ RealTimeAlarm = CLOCK_REALTIME_ALARM,
+ BootTimeAlarm = CLOCK_BOOTTIME_ALARM,
+};
+
+template <ClockId Id>
+class Clock
+{
+ public:
+ using rep = SdEventDuration::rep;
+ using period = SdEventDuration::period;
+ using duration = SdEventDuration;
+ using time_point = std::chrono::time_point<Clock>;
+ static constexpr bool is_steady = Id == ClockId::Monotonic;
+
+ Clock(const Event& event);
+ Clock(Event&& event);
+
+ time_point now() const;
+
+ private:
+ const Event event;
+};
+
+} // namespace sdeventplus
diff --git a/src/sdeventplus/internal/sdevent.hpp b/src/sdeventplus/internal/sdevent.hpp
index a3672d1..4baff05 100644
--- a/src/sdeventplus/internal/sdevent.hpp
+++ b/src/sdeventplus/internal/sdevent.hpp
@@ -18,6 +18,10 @@
virtual sd_event* sd_event_unref(sd_event* event) const = 0;
virtual int sd_event_loop(sd_event* event) const = 0;
+
+ virtual int sd_event_now(sd_event* event, clockid_t clock,
+ uint64_t* usec) const = 0;
+
virtual int sd_event_get_watchdog(sd_event* event) const = 0;
virtual int sd_event_set_watchdog(sd_event* event, int b) const = 0;
@@ -74,6 +78,12 @@
return ::sd_event_loop(event);
}
+ int sd_event_now(sd_event* event, clockid_t clock,
+ uint64_t* usec) const override
+ {
+ return ::sd_event_now(event, clock, usec);
+ }
+
int sd_event_get_watchdog(sd_event* event) const override
{
return ::sd_event_get_watchdog(event);
diff --git a/src/sdeventplus/internal/utils.hpp b/src/sdeventplus/internal/utils.hpp
new file mode 100644
index 0000000..253e10d
--- /dev/null
+++ b/src/sdeventplus/internal/utils.hpp
@@ -0,0 +1,12 @@
+#pragma once
+
+#include <chrono>
+
+namespace sdeventplus
+{
+
+// Defined by systemd taking uint64_t usec params
+using SdEventDuration =
+ std::chrono::duration<uint64_t, std::chrono::microseconds::period>;
+
+} // namespace sdeventplus
diff --git a/src/sdeventplus/test/sdevent.hpp b/src/sdeventplus/test/sdevent.hpp
index 1cb723f..5f0e400 100644
--- a/src/sdeventplus/test/sdevent.hpp
+++ b/src/sdeventplus/test/sdevent.hpp
@@ -18,6 +18,9 @@
MOCK_CONST_METHOD1(sd_event_unref, sd_event*(sd_event*));
MOCK_CONST_METHOD1(sd_event_loop, int(sd_event*));
+
+ MOCK_CONST_METHOD3(sd_event_now, int(sd_event*, clockid_t, uint64_t*));
+
MOCK_CONST_METHOD1(sd_event_get_watchdog, int(sd_event*));
MOCK_CONST_METHOD2(sd_event_set_watchdog, int(sd_event*, int b));
diff --git a/test/Makefile.am b/test/Makefile.am
index 1b4ee1e..d1923fa 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -7,6 +7,11 @@
check_PROGRAMS =
TESTS = $(check_PROGRAMS)
+check_PROGRAMS += clock
+clock_SOURCES = clock.cpp
+clock_CPPFLAGS = $(gtest_cppflags)
+clock_LDADD = $(gtest_ldadd)
+
check_PROGRAMS += event
event_SOURCES = event.cpp
event_CPPFLAGS = $(gtest_cppflags)
diff --git a/test/clock.cpp b/test/clock.cpp
new file mode 100644
index 0000000..e004341
--- /dev/null
+++ b/test/clock.cpp
@@ -0,0 +1,58 @@
+#include <cerrno>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <sdeventplus/clock.hpp>
+#include <sdeventplus/event.hpp>
+#include <sdeventplus/exception.hpp>
+#include <sdeventplus/test/sdevent.hpp>
+#include <systemd/sd-event.h>
+#include <type_traits>
+#include <utility>
+
+namespace sdeventplus
+{
+namespace
+{
+
+using testing::DoAll;
+using testing::Return;
+using testing::SetArgPointee;
+
+class ClockTest : public testing::Test
+{
+ protected:
+ testing::StrictMock<test::SdEventMock> mock;
+ sd_event* const expected_event = reinterpret_cast<sd_event*>(1234);
+};
+
+TEST_F(ClockTest, CopyEvent)
+{
+ Event event(expected_event, std::false_type(), &mock);
+
+ EXPECT_CALL(mock, sd_event_ref(expected_event))
+ .WillOnce(Return(expected_event));
+ Clock<ClockId::RealTime> clock(event);
+ EXPECT_CALL(mock, sd_event_now(expected_event, CLOCK_REALTIME, testing::_))
+ .WillOnce(DoAll(SetArgPointee<2>(2000000), Return(0)));
+ EXPECT_EQ(Clock<ClockId::RealTime>::time_point(std::chrono::seconds{2}),
+ clock.now());
+
+ EXPECT_CALL(mock, sd_event_unref(expected_event))
+ .Times(2)
+ .WillRepeatedly(Return(nullptr));
+}
+
+TEST_F(ClockTest, MoveEvent)
+{
+ Event event(expected_event, std::false_type(), &mock);
+
+ Clock<ClockId::Monotonic> clock(std::move(event));
+ EXPECT_CALL(mock, sd_event_now(expected_event, CLOCK_MONOTONIC, testing::_))
+ .WillOnce(Return(-EINVAL));
+ EXPECT_THROW(clock.now(), SdEventError);
+
+ EXPECT_CALL(mock, sd_event_unref(expected_event)).WillOnce(Return(nullptr));
+}
+
+} // namespace
+} // namespace sdeventplus