source/*: Allow copies to be made
Sources are now just reference holders so we can copy them freely.
Change-Id: I263219de83341473c333a29cf651ae82428a208a
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/src/sdeventplus/source/base.cpp b/src/sdeventplus/source/base.cpp
index bd4a42a..6b80430 100644
--- a/src/sdeventplus/source/base.cpp
+++ b/src/sdeventplus/source/base.cpp
@@ -123,6 +123,13 @@
return get_userdata().prepare;
}
+sd_event_source* Base::ref(sd_event_source* const& source,
+ const internal::SdEvent*& sdevent, bool& owned)
+{
+ owned = true;
+ return sdevent->sd_event_source_ref(source);
+}
+
void Base::drop(sd_event_source*&& source, const internal::SdEvent*& sdevent,
bool& owned)
{
diff --git a/src/sdeventplus/source/base.hpp b/src/sdeventplus/source/base.hpp
index 4c3ed79..2e4f48a 100644
--- a/src/sdeventplus/source/base.hpp
+++ b/src/sdeventplus/source/base.hpp
@@ -9,7 +9,7 @@
#include <sdeventplus/event.hpp>
#include <sdeventplus/internal/utils.hpp>
#include <sdeventplus/types.hpp>
-#include <stdplus/handle/managed.hpp>
+#include <stdplus/handle/copyable.hpp>
#include <systemd/sd-bus.h>
#include <type_traits>
#include <utility>
@@ -46,6 +46,8 @@
Base(Base&& other) = default;
Base& operator=(Base&& other) = default;
+ Base(const Base& other) = default;
+ Base& operator=(const Base& other) = default;
virtual ~Base() = default;
/** @brief Gets the underlying sd_event_source
@@ -194,11 +196,13 @@
}
private:
+ static sd_event_source* ref(sd_event_source* const& source,
+ const internal::SdEvent*& sdevent, bool& owned);
static void drop(sd_event_source*&& source,
const internal::SdEvent*& sdevent, bool& owned);
- stdplus::Managed<sd_event_source*, const internal::SdEvent*,
- bool>::Handle<drop>
+ stdplus::Copyable<sd_event_source*, const internal::SdEvent*,
+ bool>::Handle<drop, ref>
source;
/** @brief A wrapper around deleting the heap allocated base class
diff --git a/test/source/base.cpp b/test/source/base.cpp
index 3673e24..43e70ff 100644
--- a/test/source/base.cpp
+++ b/test/source/base.cpp
@@ -207,6 +207,37 @@
destroy(userdata);
}
+TEST_F(BaseTest, CopyCorrectness)
+{
+ std::unique_ptr<BaseImpl> base1, base2;
+ std::function<void()> destroy;
+ std::tie(base1, destroy) = make_base(*event, expected_source);
+ set_prepare_placeholder(*base1);
+ EXPECT_TRUE(base1->get_prepare());
+
+ EXPECT_CALL(mock, sd_event_ref(expected_event))
+ .WillOnce(Return(expected_event));
+ EXPECT_CALL(mock, sd_event_source_ref(expected_source))
+ .WillOnce(Return(expected_source));
+ base2 = std::make_unique<BaseImpl>(*base1);
+ EXPECT_EQ(&base1->get_prepare(), &base2->get_prepare());
+
+ empty_base(std::move(*base1));
+ EXPECT_THROW(base1->get_prepare(), std::bad_optional_access);
+ EXPECT_CALL(mock, sd_event_ref(expected_event))
+ .WillOnce(Return(expected_event));
+ EXPECT_CALL(mock, sd_event_source_ref(expected_source))
+ .WillOnce(Return(expected_source));
+ *base1 = *base2;
+ EXPECT_EQ(&base1->get_prepare(), &base2->get_prepare());
+
+ expect_base_destruct(*event, expected_source);
+ base2.reset();
+ expect_base_destruct(*event, expected_source);
+ base1.reset();
+ destroy();
+}
+
class BaseMethodTest : public BaseTest
{
protected:
diff --git a/test/source/child.cpp b/test/source/child.cpp
index 5dc06b9..71a8789 100644
--- a/test/source/child.cpp
+++ b/test/source/child.cpp
@@ -162,6 +162,39 @@
}
};
+TEST_F(ChildMethodTest, Copy)
+{
+ EXPECT_CALL(mock, sd_event_ref(expected_event))
+ .WillOnce(Return(expected_event));
+ EXPECT_CALL(mock, sd_event_source_ref(expected_source))
+ .WillOnce(Return(expected_source));
+ auto child2 = std::make_unique<Child>(*child);
+ {
+ EXPECT_CALL(mock, sd_event_ref(expected_event))
+ .WillOnce(Return(expected_event));
+ EXPECT_CALL(mock, sd_event_source_ref(expected_source))
+ .WillOnce(Return(expected_source));
+ Child child3(*child);
+
+ expect_destruct();
+ EXPECT_CALL(mock, sd_event_ref(expected_event))
+ .WillOnce(Return(expected_event));
+ EXPECT_CALL(mock, sd_event_source_ref(expected_source))
+ .WillOnce(Return(expected_source));
+ *child2 = child3;
+
+ expect_destruct();
+ }
+
+ // Delete the original child
+ child2.swap(child);
+ expect_destruct();
+ child2.reset();
+
+ // Make sure our new copy can still access data
+ child->set_callback(nullptr);
+}
+
TEST_F(ChildMethodTest, GetPidSuccess)
{
const pid_t pid = 32;
diff --git a/test/source/event.cpp b/test/source/event.cpp
index 1d5a877..0d86617 100644
--- a/test/source/event.cpp
+++ b/test/source/event.cpp
@@ -186,6 +186,63 @@
EXPECT_EQ(0, completions);
}
+TEST_F(EventTest, CopyConstruct)
+{
+ EXPECT_CALL(mock, sd_event_ref(expected_event))
+ .WillOnce(Return(expected_event));
+ sd_event_destroy_t destroy;
+ void* userdata;
+ {
+ testing::InSequence seq;
+ EXPECT_CALL(mock, sd_event_source_set_destroy_callback(expected_source,
+ testing::_))
+ .WillOnce(DoAll(SaveArg<1>(&destroy), Return(0)));
+ EXPECT_CALL(mock,
+ sd_event_source_set_userdata(expected_source, testing::_))
+ .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
+ EXPECT_CALL(mock, sd_event_source_get_userdata(expected_source))
+ .WillRepeatedly(ReturnPointee(&userdata));
+ }
+ sd_event_handler_t handler;
+ EXPECT_CALL(mock, sd_event_add_exit(expected_event, testing::_, testing::_,
+ nullptr))
+ .WillOnce(DoAll(SetArgPointee<1>(expected_source), SaveArg<2>(&handler),
+ Return(0)));
+ auto exit = std::make_unique<Exit>(*event, [](EventBase&) {});
+
+ EXPECT_CALL(mock, sd_event_ref(expected_event))
+ .WillOnce(Return(expected_event));
+ EXPECT_CALL(mock, sd_event_source_ref(expected_source))
+ .WillOnce(Return(expected_source));
+ auto exit2 = std::make_unique<Exit>(*exit);
+ {
+ EXPECT_CALL(mock, sd_event_ref(expected_event))
+ .WillOnce(Return(expected_event));
+ EXPECT_CALL(mock, sd_event_source_ref(expected_source))
+ .WillOnce(Return(expected_source));
+ Exit exit3(*exit);
+
+ expect_destruct();
+ EXPECT_CALL(mock, sd_event_ref(expected_event))
+ .WillOnce(Return(expected_event));
+ EXPECT_CALL(mock, sd_event_source_ref(expected_source))
+ .WillOnce(Return(expected_source));
+ *exit2 = exit3;
+
+ expect_destruct();
+ }
+
+ // Delete the original exit
+ expect_destruct();
+ exit.reset();
+
+ // Make sure our new copy can still access data
+ exit2->set_callback(nullptr);
+ expect_destruct();
+ exit2.reset();
+ destroy(userdata);
+}
+
} // namespace
} // namespace source
} // namespace sdeventplus
diff --git a/test/source/io.cpp b/test/source/io.cpp
index bafdeb8..e8abb82 100644
--- a/test/source/io.cpp
+++ b/test/source/io.cpp
@@ -162,6 +162,39 @@
}
};
+TEST_F(IOMethodTest, Copy)
+{
+ EXPECT_CALL(mock, sd_event_ref(expected_event))
+ .WillOnce(Return(expected_event));
+ EXPECT_CALL(mock, sd_event_source_ref(expected_source))
+ .WillOnce(Return(expected_source));
+ auto io2 = std::make_unique<IO>(*io);
+ {
+ EXPECT_CALL(mock, sd_event_ref(expected_event))
+ .WillOnce(Return(expected_event));
+ EXPECT_CALL(mock, sd_event_source_ref(expected_source))
+ .WillOnce(Return(expected_source));
+ IO io3(*io);
+
+ expect_destruct();
+ EXPECT_CALL(mock, sd_event_ref(expected_event))
+ .WillOnce(Return(expected_event));
+ EXPECT_CALL(mock, sd_event_source_ref(expected_source))
+ .WillOnce(Return(expected_source));
+ *io2 = io3;
+
+ expect_destruct();
+ }
+
+ // Delete the original IO
+ io2.swap(io);
+ expect_destruct();
+ io2.reset();
+
+ // Make sure our new copy can still access data
+ io->set_callback(nullptr);
+}
+
TEST_F(IOMethodTest, GetFdSuccess)
{
const int fd = 5;
diff --git a/test/source/signal.cpp b/test/source/signal.cpp
index 209f2a7..9ac0f67 100644
--- a/test/source/signal.cpp
+++ b/test/source/signal.cpp
@@ -161,6 +161,39 @@
}
};
+TEST_F(SignalMethodTest, Copy)
+{
+ EXPECT_CALL(mock, sd_event_ref(expected_event))
+ .WillOnce(Return(expected_event));
+ EXPECT_CALL(mock, sd_event_source_ref(expected_source))
+ .WillOnce(Return(expected_source));
+ auto signal2 = std::make_unique<Signal>(*signal);
+ {
+ EXPECT_CALL(mock, sd_event_ref(expected_event))
+ .WillOnce(Return(expected_event));
+ EXPECT_CALL(mock, sd_event_source_ref(expected_source))
+ .WillOnce(Return(expected_source));
+ Signal signal3(*signal);
+
+ expect_destruct();
+ EXPECT_CALL(mock, sd_event_ref(expected_event))
+ .WillOnce(Return(expected_event));
+ EXPECT_CALL(mock, sd_event_source_ref(expected_source))
+ .WillOnce(Return(expected_source));
+ *signal2 = signal3;
+
+ expect_destruct();
+ }
+
+ // Delete the original signal
+ signal2.swap(signal);
+ expect_destruct();
+ signal2.reset();
+
+ // Make sure our new copy can still access data
+ signal->set_callback(nullptr);
+}
+
TEST_F(SignalMethodTest, GetSignalSuccess)
{
const int sig = SIGTERM;
diff --git a/test/source/time.cpp b/test/source/time.cpp
index 569d2c0..01d4ae2 100644
--- a/test/source/time.cpp
+++ b/test/source/time.cpp
@@ -164,6 +164,39 @@
}
};
+TEST_F(TimeMethodTest, Copy)
+{
+ EXPECT_CALL(mock, sd_event_ref(expected_event))
+ .WillOnce(Return(expected_event));
+ EXPECT_CALL(mock, sd_event_source_ref(expected_source))
+ .WillOnce(Return(expected_source));
+ auto time2 = std::make_unique<Time<id>>(*time);
+ {
+ EXPECT_CALL(mock, sd_event_ref(expected_event))
+ .WillOnce(Return(expected_event));
+ EXPECT_CALL(mock, sd_event_source_ref(expected_source))
+ .WillOnce(Return(expected_source));
+ Time<id> time3(*time);
+
+ expect_time_destroy(expected_event, expected_source);
+ EXPECT_CALL(mock, sd_event_ref(expected_event))
+ .WillOnce(Return(expected_event));
+ EXPECT_CALL(mock, sd_event_source_ref(expected_source))
+ .WillOnce(Return(expected_source));
+ *time2 = time3;
+
+ expect_time_destroy(expected_event, expected_source);
+ }
+
+ // Delete the original time
+ time2.swap(time);
+ expect_time_destroy(expected_event, expected_source);
+ time2.reset();
+
+ // Make sure our new copy can still access data
+ time->set_callback(nullptr);
+}
+
TEST_F(TimeMethodTest, SetTimeSuccess)
{
EXPECT_CALL(mock, sd_event_source_set_time(expected_source, 1000000))