diff options
| author | William A. Kennington III <wak@google.com> | 2018-07-17 14:40:14 -0700 |
|---|---|---|
| committer | William A. Kennington III <wak@google.com> | 2018-07-17 14:40:14 -0700 |
| commit | 48c427510b0fd9ead21978f8e20f7394c95fde8d (patch) | |
| tree | 72c7d98f537f73be1dceee344fdf2114c9b5b2e3 | |
| parent | 65db863e625b04e2094849702eca8a63958f6279 (diff) | |
| download | sdeventplus-48c427510b0fd9ead21978f8e20f7394c95fde8d.tar.gz sdeventplus-48c427510b0fd9ead21978f8e20f7394c95fde8d.zip | |
source/base: Add the prepare callback functionality
| -rw-r--r-- | src/sdeventplus/internal/sdevent.hpp | 8 | ||||
| -rw-r--r-- | src/sdeventplus/source/base.cpp | 47 | ||||
| -rw-r--r-- | src/sdeventplus/source/base.hpp | 9 | ||||
| -rw-r--r-- | test/source/base.cpp | 70 |
4 files changed, 134 insertions, 0 deletions
diff --git a/src/sdeventplus/internal/sdevent.hpp b/src/sdeventplus/internal/sdevent.hpp index e6c420c..dfb6285 100644 --- a/src/sdeventplus/internal/sdevent.hpp +++ b/src/sdeventplus/internal/sdevent.hpp @@ -32,6 +32,9 @@ class SdEvent virtual int sd_event_source_set_description(sd_event_source* source, const char* description) const = 0; + virtual int + sd_event_source_set_prepare(sd_event_source* source, + sd_event_handler_t callback) const = 0; virtual int sd_event_source_get_pending(sd_event_source* source) const = 0; virtual int sd_event_source_get_priority(sd_event_source* source, int64_t* priority) const = 0; @@ -101,6 +104,11 @@ class SdEventImpl : public SdEvent { return ::sd_event_source_set_description(source, description); } + int sd_event_source_set_prepare(sd_event_source* source, + sd_event_handler_t callback) const override + { + return ::sd_event_source_set_prepare(source, callback); + } int sd_event_source_get_pending(sd_event_source* source) const override { return ::sd_event_source_get_pending(source); diff --git a/src/sdeventplus/source/base.cpp b/src/sdeventplus/source/base.cpp index d99d562..d361333 100644 --- a/src/sdeventplus/source/base.cpp +++ b/src/sdeventplus/source/base.cpp @@ -1,4 +1,5 @@ #include <cerrno> +#include <cstdio> #include <exception> #include <sdeventplus/exception.hpp> #include <sdeventplus/internal/sdevent.hpp> @@ -17,6 +18,30 @@ Base::~Base() set_enabled(SD_EVENT_OFF); } +int Base::prepareCallback() +{ + try + { + prepare(*this); + return 0; + } + catch (const std::system_error& e) + { + fprintf(stderr, "sdeventplus: prepareCallback: %s\n", e.what()); + return -e.code().value(); + } + catch (const std::exception& e) + { + fprintf(stderr, "sdeventplus: prepareCallback: %s\n", e.what()); + return -ENOSYS; + } + catch (...) + { + fprintf(stderr, "sdeventplus: prepareCallback: Unknown error\n"); + return -ENOSYS; + } +} + const char* Base::get_description() { const char* description; @@ -38,6 +63,28 @@ void Base::set_description(const char* description) } } +static int prepare_callback(sd_event_source*, void* userdata) +{ + if (userdata == nullptr) + { + fprintf(stderr, "sdeventplus: prepare_callback: Missing userdata\n"); + return -EINVAL; + } + return reinterpret_cast<Base*>(userdata)->prepareCallback(); +} + +void Base::set_prepare(Callback&& callback) +{ + int r = sdevent->sd_event_source_set_prepare( + source.get(), callback ? prepare_callback : nullptr); + if (r < 0) + { + prepare = nullptr; + throw SdEventError(-r, "sd_event_source_set_prepare"); + } + prepare = std::move(callback); +} + int Base::get_pending() { int r = sdevent->sd_event_source_get_pending(source.get()); diff --git a/src/sdeventplus/source/base.hpp b/src/sdeventplus/source/base.hpp index 20ab820..748f340 100644 --- a/src/sdeventplus/source/base.hpp +++ b/src/sdeventplus/source/base.hpp @@ -1,6 +1,7 @@ #pragma once #include <cstdint> +#include <functional> #include <sdeventplus/internal/sdevent.hpp> #include <sdeventplus/internal/sdref.hpp> #include <systemd/sd-bus.h> @@ -14,6 +15,8 @@ namespace source class Base { public: + using Callback = std::function<void(Base& source)>; + virtual ~Base(); // We don't want to allow any kind of slicing. @@ -22,8 +25,11 @@ class Base Base(Base&& source) = delete; Base& operator=(Base&& source) = delete; + int prepareCallback(); + const char* get_description(); void set_description(const char* description); + void set_prepare(Callback&& callback); int get_pending(); int64_t get_priority(); void set_priority(int64_t priority); @@ -39,6 +45,9 @@ class Base internal::SdEvent* sdevent = &internal::sdevent_impl); Base(sd_event_source* source, std::false_type, internal::SdEvent* sdevent = &internal::sdevent_impl); + + private: + Callback prepare; }; } // namespace source diff --git a/test/source/base.cpp b/test/source/base.cpp index ce95f12..13c534a 100644 --- a/test/source/base.cpp +++ b/test/source/base.cpp @@ -1,3 +1,4 @@ +#include <cerrno> #include <gmock/gmock.h> #include <gtest/gtest.h> #include <sdeventplus/exception.hpp> @@ -5,6 +6,7 @@ #include <sdeventplus/source/base.hpp> #include <sdeventplus/test/sdevent.hpp> #include <string> +#include <system_error> #include <type_traits> namespace sdeventplus @@ -16,6 +18,7 @@ namespace using testing::DoAll; using testing::Return; +using testing::SaveArg; using testing::SetArgPointee; class BaseImpl : public Base @@ -132,6 +135,73 @@ TEST_F(BaseMethodTest, SetDescriptionError) EXPECT_THROW(base->set_description(expected), SdEventError); } +TEST_F(BaseMethodTest, SetPrepareCallback) +{ + bool completed = false; + Base::Callback callback = [&completed](Base&) { completed = true; }; + sd_event_handler_t event_handler; + EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_)) + .WillOnce(DoAll(SaveArg<1>(&event_handler), Return(0))); + base->set_prepare(std::move(callback)); + EXPECT_FALSE(callback); + EXPECT_FALSE(completed); + + EXPECT_EQ(0, event_handler(nullptr, base.get())); + EXPECT_TRUE(completed); +} + +TEST_F(BaseMethodTest, SetPrepareCallbackNoUserdata) +{ + Base::Callback callback = [](Base&) {}; + sd_event_handler_t event_handler; + EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_)) + .WillOnce(DoAll(SaveArg<1>(&event_handler), Return(0))); + base->set_prepare(std::move(callback)); + EXPECT_FALSE(callback); + + EXPECT_EQ(-EINVAL, event_handler(nullptr, nullptr)); +} + +TEST_F(BaseMethodTest, SetPrepareNull) +{ + EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, nullptr)) + .WillOnce(Return(0)); + base->set_prepare(nullptr); + EXPECT_EQ(-ENOSYS, base->prepareCallback()); +} + +TEST_F(BaseMethodTest, SetPrepareSystemError) +{ + Base::Callback callback = [](Base&) { + throw std::system_error(EBUSY, std::generic_category()); + }; + EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_)) + .WillOnce(Return(0)); + base->set_prepare(std::move(callback)); + EXPECT_FALSE(callback); + EXPECT_EQ(-EBUSY, base->prepareCallback()); +} + +TEST_F(BaseMethodTest, SetPrepareUnknownException) +{ + Base::Callback callback = [](Base&) { throw static_cast<int>(1); }; + EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_)) + .WillOnce(Return(0)); + base->set_prepare(std::move(callback)); + EXPECT_FALSE(callback); + EXPECT_EQ(-ENOSYS, base->prepareCallback()); +} + +TEST_F(BaseMethodTest, SetPrepareError) +{ + Base::Callback callback = [](Base&) {}; + EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_)) + .WillOnce(Return(-EINVAL)); + EXPECT_THROW(base->set_prepare(std::move(callback)), SdEventError); + EXPECT_TRUE(callback); + EXPECT_EQ(-ENOSYS, base->prepareCallback()); +} + TEST_F(BaseMethodTest, GetPendingSuccess) { EXPECT_CALL(mock, sd_event_source_get_pending(expected_source)) |

