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::_))