event: Add non-owning constructor
This allows internal store event objects without having to contain
circular references. A circular reference in an event source will cause
the event loop from ever cleaning up correctly.
Change-Id: I23fe0c95093953071216cf1deeb17e79defb7ffb
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/src/sdeventplus/event.cpp b/src/sdeventplus/event.cpp
index 601c0df..93f9afa 100644
--- a/src/sdeventplus/event.cpp
+++ b/src/sdeventplus/event.cpp
@@ -4,19 +4,25 @@
#include <sdeventplus/internal/utils.hpp>
#include <systemd/sd-event.h>
#include <type_traits>
+#include <utility>
namespace sdeventplus
{
Event::Event(sd_event* event, const internal::SdEvent* sdevent) :
- sdevent(sdevent), event(event, sdevent)
+ sdevent(sdevent), event(event, sdevent, true)
{
}
Event::Event(sd_event* event, std::false_type,
const internal::SdEvent* sdevent) :
sdevent(sdevent),
- event(std::move(event), sdevent)
+ event(std::move(event), sdevent, true)
+{
+}
+
+Event::Event(const Event& other, sdeventplus::internal::NoOwn) :
+ sdevent(other.sdevent), event(other.get(), other.getSdEvent(), false)
{
}
@@ -112,14 +118,20 @@
sdevent, get(), b);
}
-sd_event* Event::ref(sd_event* const& event, const internal::SdEvent*& sdevent)
+sd_event* Event::ref(sd_event* const& event, const internal::SdEvent*& sdevent,
+ bool& owned)
{
+ owned = true;
return sdevent->sd_event_ref(event);
}
-void Event::drop(sd_event*&& event, const internal::SdEvent*& sdevent)
+void Event::drop(sd_event*&& event, const internal::SdEvent*& sdevent,
+ bool& owned)
{
- sdevent->sd_event_unref(event);
+ if (owned)
+ {
+ sdevent->sd_event_unref(event);
+ }
}
} // namespace sdeventplus
diff --git a/src/sdeventplus/event.hpp b/src/sdeventplus/event.hpp
index f234e5c..e17e743 100644
--- a/src/sdeventplus/event.hpp
+++ b/src/sdeventplus/event.hpp
@@ -3,6 +3,7 @@
#include <optional>
#include <sdeventplus/internal/sdevent.hpp>
#include <sdeventplus/internal/utils.hpp>
+#include <sdeventplus/types.hpp>
#include <stdplus/handle/copyable.hpp>
#include <systemd/sd-event.h>
@@ -32,8 +33,8 @@
/** @brief Constructs a new event from sd_event
* Does not take a reference on the passed in sd_event
- * NOTE: This will still take a reference during future copies
- * Useful for first creation of an sd_event
+ * @note This will still take a reference during future copies
+ * Useful for first creation of an sd_event
*
* @param[in] event - The sd_event to wrap
* @param[in] - Denotes no reference taken during construction
@@ -43,6 +44,17 @@
Event(sd_event* event, std::false_type,
const internal::SdEvent* sdevent = &internal::sdevent_impl);
+ /** @brief Constructs a new non-owning event from an event
+ * Does not take a reference on the passed in sd_event
+ * Does not release the reference it is given
+ * @note This will still take a reference during future copies
+ * @internal
+ *
+ * @param[in] other - The other Event to copy
+ * @param[in] - Denotes no reference taken or release
+ */
+ Event(const Event& other, sdeventplus::internal::NoOwn);
+
/** @brief Create a wrapped event around sd_event_new()
*
* @param[in] sdevent - Optional underlying sd_event implementation
@@ -147,11 +159,13 @@
private:
static sd_event* ref(sd_event* const& event,
- const internal::SdEvent*& sdevent);
- static void drop(sd_event*&& event, const internal::SdEvent*& sdevent);
+ const internal::SdEvent*& sdevent, bool& owned);
+ static void drop(sd_event*&& event, const internal::SdEvent*& sdevent,
+ bool& owned);
const internal::SdEvent* sdevent;
- stdplus::Copyable<sd_event*, const internal::SdEvent*>::Handle<drop, ref>
+ stdplus::Copyable<sd_event*, const internal::SdEvent*, bool>::Handle<drop,
+ ref>
event;
};
diff --git a/src/sdeventplus/types.hpp b/src/sdeventplus/types.hpp
new file mode 100644
index 0000000..4508f3e
--- /dev/null
+++ b/src/sdeventplus/types.hpp
@@ -0,0 +1,15 @@
+#pragma once
+
+namespace sdeventplus
+{
+namespace internal
+{
+
+/* @brief Indicates that the container should not own the underlying
+ * sd_event primative */
+struct NoOwn
+{
+};
+
+} // namespace internal
+} // namespace sdeventplus
diff --git a/test/event.cpp b/test/event.cpp
index 1bf5976..ff574be 100644
--- a/test/event.cpp
+++ b/test/event.cpp
@@ -43,6 +43,40 @@
EXPECT_CALL(mock, sd_event_unref(expected_event)).WillOnce(Return(nullptr));
}
+TEST_F(EventTest, CopyEventNoOwn)
+{
+ Event event(expected_event, std::false_type(), &mock);
+ EXPECT_EQ(&mock, event.getSdEvent());
+ EXPECT_EQ(expected_event, event.get());
+
+ Event event_noown(event, sdeventplus::internal::NoOwn());
+ EXPECT_EQ(&mock, event_noown.getSdEvent());
+ EXPECT_EQ(expected_event, event_noown.get());
+
+ EXPECT_CALL(mock, sd_event_unref(expected_event)).WillOnce(Return(nullptr));
+}
+
+TEST_F(EventTest, CopyEventNoOwnCopy)
+{
+ Event event(expected_event, std::false_type(), &mock);
+ EXPECT_EQ(&mock, event.getSdEvent());
+ EXPECT_EQ(expected_event, event.get());
+
+ Event event_noown(event, sdeventplus::internal::NoOwn());
+ EXPECT_EQ(&mock, event_noown.getSdEvent());
+ EXPECT_EQ(expected_event, event_noown.get());
+
+ EXPECT_CALL(mock, sd_event_ref(expected_event))
+ .WillOnce(Return(expected_event));
+ Event event2(event_noown);
+ EXPECT_EQ(&mock, event2.getSdEvent());
+ EXPECT_EQ(expected_event, event2.get());
+
+ EXPECT_CALL(mock, sd_event_unref(expected_event))
+ .WillOnce(Return(nullptr))
+ .WillOnce(Return(nullptr));
+}
+
TEST_F(EventTest, GetNewEvent)
{
EXPECT_CALL(mock, sd_event_new(testing::_))