diff options
| author | William A. Kennington III <wak@google.com> | 2018-07-22 18:15:59 -0700 |
|---|---|---|
| committer | William A. Kennington III <wak@google.com> | 2018-07-22 18:32:56 -0700 |
| commit | a3a38504c75fd72233f20a42065184d3727ac6c8 (patch) | |
| tree | 4a486c5c269873ca28dc902dd9d8da02e2afc537 | |
| parent | ce80c3ff01ef7c4086108cacbf61da5255248884 (diff) | |
| download | sdeventplus-a3a38504c75fd72233f20a42065184d3727ac6c8.tar.gz sdeventplus-a3a38504c75fd72233f20a42065184d3727ac6c8.zip | |
source/signal: Implement
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | src/Makefile.am | 3 | ||||
| -rw-r--r-- | src/sdeventplus/internal/sdevent.cpp | 5 | ||||
| -rw-r--r-- | src/sdeventplus/internal/sdevent.hpp | 13 | ||||
| -rw-r--r-- | src/sdeventplus/source/signal.cpp | 52 | ||||
| -rw-r--r-- | src/sdeventplus/source/signal.hpp | 35 | ||||
| -rw-r--r-- | src/sdeventplus/test/sdevent.hpp | 4 | ||||
| -rw-r--r-- | test/Makefile.am | 5 | ||||
| -rw-r--r-- | test/source/signal.cpp | 160 |
9 files changed, 278 insertions, 0 deletions
@@ -51,4 +51,5 @@ Makefile.in /test/source_base /test/source_event /test/source_io +/test/source_signal /test/source_time diff --git a/src/Makefile.am b/src/Makefile.am index 74f01f5..236e347 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -30,6 +30,9 @@ libsdeventplus_la_SOURCES += sdeventplus/source/event.cpp nobase_include_HEADERS += sdeventplus/source/io.hpp libsdeventplus_la_SOURCES += sdeventplus/source/io.cpp +nobase_include_HEADERS += sdeventplus/source/signal.hpp +libsdeventplus_la_SOURCES += sdeventplus/source/signal.cpp + nobase_include_HEADERS += sdeventplus/source/time.hpp libsdeventplus_la_SOURCES += sdeventplus/source/time.cpp diff --git a/src/sdeventplus/internal/sdevent.cpp b/src/sdeventplus/internal/sdevent.cpp index 467a3c3..ad5114c 100644 --- a/src/sdeventplus/internal/sdevent.cpp +++ b/src/sdeventplus/internal/sdevent.cpp @@ -244,6 +244,11 @@ int SdEventImpl::sd_event_source_set_time_accuracy(sd_event_source* source, return ::sd_event_source_set_time_accuracy(source, usec); } +int SdEventImpl::sd_event_source_get_signal(sd_event_source* source) const +{ + return ::sd_event_source_get_signal(source); +} + SdEventImpl sdevent_impl; } // namespace internal diff --git a/src/sdeventplus/internal/sdevent.hpp b/src/sdeventplus/internal/sdevent.hpp index 62acbbe..42427eb 100644 --- a/src/sdeventplus/internal/sdevent.hpp +++ b/src/sdeventplus/internal/sdevent.hpp @@ -25,6 +25,9 @@ class SdEvent uint64_t accuracy, sd_event_time_handler_t callback, void* userdata) const = 0; + virtual int sd_event_add_signal(sd_event* event, sd_event_source** source, + int sig, sd_event_signal_handler_t callback, + void* userdata) const = 0; virtual int sd_event_add_defer(sd_event* event, sd_event_source** source, sd_event_handler_t callback, void* userdata) const = 0; @@ -96,6 +99,7 @@ class SdEvent uint64_t* usec) const = 0; virtual int sd_event_source_set_time_accuracy(sd_event_source* source, uint64_t usec) const = 0; + virtual int sd_event_source_get_signal(sd_event_source*) const = 0; }; class SdEventImpl : public SdEvent @@ -113,6 +117,14 @@ class SdEventImpl : public SdEvent clockid_t clock, uint64_t usec, uint64_t accuracy, sd_event_time_handler_t callback, void* userdata) const override; + + int sd_event_add_signal(sd_event* event, sd_event_source** source, int sig, + sd_event_signal_handler_t callback, + void* userdata) const override + { + return ::sd_event_add_signal(event, source, sig, callback, userdata); + } + int sd_event_add_defer(sd_event* event, sd_event_source** source, sd_event_handler_t callback, void* userdata) const override; @@ -180,6 +192,7 @@ class SdEventImpl : public SdEvent uint64_t* usec) const override; int sd_event_source_set_time_accuracy(sd_event_source* source, uint64_t usec) const override; + int sd_event_source_get_signal(sd_event_source*) const override; }; extern SdEventImpl sdevent_impl; diff --git a/src/sdeventplus/source/signal.cpp b/src/sdeventplus/source/signal.cpp new file mode 100644 index 0000000..1df3a29 --- /dev/null +++ b/src/sdeventplus/source/signal.cpp @@ -0,0 +1,52 @@ +#include <sdeventplus/exception.hpp> +#include <sdeventplus/source/signal.hpp> +#include <type_traits> +#include <utility> + +namespace sdeventplus +{ +namespace source +{ + +Signal::Signal(const Event& event, int sig, Callback&& callback) : + Base(event, create_source(event, sig), std::false_type()), + callback(std::move(callback)) +{ +} + +int Signal::get_signal() const +{ + int r = event.getSdEvent()->sd_event_source_get_signal(source.get()); + if (r < 0) + { + throw SdEventError(-r, "sd_event_source_get_signal"); + } + return r; +} + +const Signal::Callback& Signal::get_callback() const +{ + return callback; +} + +sd_event_source* Signal::create_source(const Event& event, int sig) +{ + sd_event_source* source; + int r = event.getSdEvent()->sd_event_add_signal(event.get(), &source, sig, + signalCallback, nullptr); + if (r < 0) + { + throw SdEventError(-r, "sd_event_add_signal"); + } + return source; +} + +int Signal::signalCallback(sd_event_source* source, + const struct signalfd_siginfo* si, void* userdata) +{ + return sourceCallback<Callback, Signal, &Signal::get_callback>( + "signalCallback", source, userdata, si); +} + +} // namespace source +} // namespace sdeventplus diff --git a/src/sdeventplus/source/signal.hpp b/src/sdeventplus/source/signal.hpp new file mode 100644 index 0000000..ec8d227 --- /dev/null +++ b/src/sdeventplus/source/signal.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include <functional> +#include <sdeventplus/source/base.hpp> +#include <sys/signalfd.h> + +namespace sdeventplus +{ +namespace source +{ + +class Signal : public Base +{ + public: + using Callback = + std::function<void(Signal& source, const struct signalfd_siginfo* si)>; + + Signal(const Event& event, int sig, Callback&& callback); + + int get_signal() const; + + private: + Callback callback; + + const Callback& get_callback() const; + + static sd_event_source* create_source(const Event& event, int sig); + + static int signalCallback(sd_event_source* source, + const struct signalfd_siginfo* si, + void* userdata); +}; + +} // namespace source +} // namespace sdeventplus diff --git a/src/sdeventplus/test/sdevent.hpp b/src/sdeventplus/test/sdevent.hpp index 28c484d..37b4464 100644 --- a/src/sdeventplus/test/sdevent.hpp +++ b/src/sdeventplus/test/sdevent.hpp @@ -23,6 +23,9 @@ class SdEventMock : public internal::SdEvent MOCK_CONST_METHOD7(sd_event_add_time, int(sd_event*, sd_event_source**, clockid_t, uint64_t, uint64_t, sd_event_time_handler_t, void*)); + MOCK_CONST_METHOD5(sd_event_add_signal, + int(sd_event*, sd_event_source**, int, + sd_event_signal_handler_t, void*)); MOCK_CONST_METHOD4(sd_event_add_defer, int(sd_event*, sd_event_source**, sd_event_handler_t, void*)); MOCK_CONST_METHOD4(sd_event_add_post, int(sd_event*, sd_event_source**, @@ -83,6 +86,7 @@ class SdEventMock : public internal::SdEvent int(sd_event_source*, uint64_t*)); MOCK_CONST_METHOD2(sd_event_source_set_time_accuracy, int(sd_event_source*, uint64_t)); + MOCK_CONST_METHOD1(sd_event_source_get_signal, int(sd_event_source*)); }; } // namespace test diff --git a/test/Makefile.am b/test/Makefile.am index 3d51b65..5a6c1bb 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -47,6 +47,11 @@ source_io_SOURCES = source/io.cpp source_io_CPPFLAGS = $(gtest_cppflags) source_io_LDADD = $(gtest_ldadd) +check_PROGRAMS += source_signal +source_signal_SOURCES = source/signal.cpp +source_signal_CPPFLAGS = $(gtest_cppflags) +source_signal_LDADD = $(gtest_ldadd) + check_PROGRAMS += source_time source_time_SOURCES = source/time.cpp source_time_CPPFLAGS = $(gtest_cppflags) diff --git a/test/source/signal.cpp b/test/source/signal.cpp new file mode 100644 index 0000000..c99aa6b --- /dev/null +++ b/test/source/signal.cpp @@ -0,0 +1,160 @@ +#include <cerrno> +#include <functional> +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <memory> +#include <sdeventplus/event.hpp> +#include <sdeventplus/exception.hpp> +#include <sdeventplus/source/signal.hpp> +#include <sdeventplus/test/sdevent.hpp> +#include <signal.h> +#include <systemd/sd-event.h> +#include <type_traits> +#include <utility> + +namespace sdeventplus +{ +namespace source +{ +namespace +{ + +using testing::DoAll; +using testing::Return; +using testing::SaveArg; +using testing::SetArgPointee; + +using UniqueEvent = std::unique_ptr<Event, std::function<void(Event*)>>; + +class SignalTest : public testing::Test +{ + protected: + testing::StrictMock<test::SdEventMock> mock; + sd_event_source* const expected_source = + reinterpret_cast<sd_event_source*>(1234); + sd_event* const expected_event = reinterpret_cast<sd_event*>(2345); + UniqueEvent event = make_event(expected_event); + + UniqueEvent make_event(sd_event* event) + { + auto deleter = [this, event](Event* e) { + EXPECT_CALL(this->mock, sd_event_unref(event)) + .WillOnce(Return(nullptr)); + delete e; + }; + return UniqueEvent(new Event(event, std::false_type(), &mock), deleter); + } + + void expect_destruct() + { + { + testing::InSequence sequence; + EXPECT_CALL(mock, sd_event_source_set_enabled(expected_source, + SD_EVENT_OFF)) + .WillOnce(Return(0)); + EXPECT_CALL(mock, sd_event_source_unref(expected_source)) + .WillOnce(Return(nullptr)); + } + EXPECT_CALL(mock, sd_event_unref(expected_event)) + .WillOnce(Return(nullptr)); + } +}; + +TEST_F(SignalTest, ConstructSuccess) +{ + const int sig = SIGALRM; + + EXPECT_CALL(mock, sd_event_ref(expected_event)) + .WillOnce(Return(expected_event)); + sd_event_signal_handler_t handler; + EXPECT_CALL(mock, sd_event_add_signal(expected_event, testing::_, sig, + testing::_, nullptr)) + .WillOnce(DoAll(SetArgPointee<1>(expected_source), SaveArg<3>(&handler), + Return(0))); + void* userdata; + EXPECT_CALL(mock, sd_event_source_set_userdata(expected_source, testing::_)) + .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr))); + int completions = 0; + const struct signalfd_siginfo* return_si; + Signal::Callback callback = [&](Signal&, + const struct signalfd_siginfo* si) { + return_si = si; + completions++; + }; + Signal signal(*event, sig, std::move(callback)); + EXPECT_FALSE(callback); + EXPECT_EQ(&signal, userdata); + EXPECT_EQ(0, completions); + + const struct signalfd_siginfo* expected_si = + reinterpret_cast<struct signalfd_siginfo*>(865); + EXPECT_EQ(0, handler(nullptr, expected_si, &signal)); + EXPECT_EQ(1, completions); + EXPECT_EQ(expected_si, return_si); + + expect_destruct(); +} + +TEST_F(SignalTest, ConstructError) +{ + const int sig = SIGALRM; + + EXPECT_CALL(mock, sd_event_add_signal(expected_event, testing::_, sig, + testing::_, nullptr)) + .WillOnce(Return(-EINVAL)); + int completions = 0; + Signal::Callback callback = [&completions](Signal&, + const struct signalfd_siginfo*) { + completions++; + }; + EXPECT_THROW(Signal(*event, sig, std::move(callback)), SdEventError); + EXPECT_TRUE(callback); + EXPECT_EQ(0, completions); +} + +class SignalMethodTest : public SignalTest +{ + protected: + std::unique_ptr<Signal> signal; + + void SetUp() + { + const int sig = SIGINT; + + EXPECT_CALL(mock, sd_event_ref(expected_event)) + .WillOnce(Return(expected_event)); + EXPECT_CALL(mock, sd_event_add_signal(expected_event, testing::_, sig, + testing::_, nullptr)) + .WillOnce(DoAll(SetArgPointee<1>(expected_source), Return(0))); + EXPECT_CALL(mock, + sd_event_source_set_userdata(expected_source, testing::_)) + .WillOnce(Return(nullptr)); + signal = std::make_unique<Signal>( + *event, sig, [](Signal&, const struct signalfd_siginfo*) {}); + } + + void TearDown() + { + expect_destruct(); + signal.reset(); + } +}; + +TEST_F(SignalMethodTest, GetSignalSuccess) +{ + const int sig = SIGTERM; + EXPECT_CALL(mock, sd_event_source_get_signal(expected_source)) + .WillOnce(Return(sig)); + EXPECT_EQ(sig, signal->get_signal()); +} + +TEST_F(SignalMethodTest, GetSignalError) +{ + EXPECT_CALL(mock, sd_event_source_get_signal(expected_source)) + .WillOnce(Return(-EINVAL)); + EXPECT_THROW(signal->get_signal(), SdEventError); +} + +} // namespace +} // namespace source +} // namespace sdeventplus |

