source/base: Support automatically configuring userdata
This makes callbacks work correctly as the systemd callback functions
need to know where to look for the object storing the real callback.
diff --git a/src/sdeventplus/internal/sdevent.hpp b/src/sdeventplus/internal/sdevent.hpp
index be8e0a8..7713cb8 100644
--- a/src/sdeventplus/internal/sdevent.hpp
+++ b/src/sdeventplus/internal/sdevent.hpp
@@ -36,6 +36,9 @@
virtual sd_event_source*
sd_event_source_unref(sd_event_source* source) const = 0;
+ virtual void* sd_event_source_set_userdata(sd_event_source* source,
+ void* userdata) const = 0;
+
virtual int
sd_event_source_get_description(sd_event_source* source,
const char** description) const = 0;
@@ -141,6 +144,12 @@
return ::sd_event_source_unref(source);
}
+ void* sd_event_source_set_userdata(sd_event_source* source,
+ void* userdata) const override
+ {
+ return ::sd_event_source_set_userdata(source, userdata);
+ }
+
int sd_event_source_get_description(sd_event_source* source,
const char** description) const override
{
diff --git a/src/sdeventplus/source/base.cpp b/src/sdeventplus/source/base.cpp
index 94a5628..83908d1 100644
--- a/src/sdeventplus/source/base.cpp
+++ b/src/sdeventplus/source/base.cpp
@@ -163,6 +163,7 @@
source(source, &internal::SdEvent::sd_event_source_ref,
&internal::SdEvent::sd_event_source_unref, event.getSdEvent())
{
+ set_userdata();
}
Base::Base(const Event& event, sd_event_source* source, std::false_type) :
@@ -170,6 +171,14 @@
&internal::SdEvent::sd_event_source_unref,
std::false_type(), event.getSdEvent())
{
+ set_userdata();
+}
+
+Base::Base(Base&& other) :
+ event(std::move(other.event)), source(std::move(other.source)),
+ prepare(std::move(other.prepare))
+{
+ set_userdata();
}
Base& Base::operator=(Base&& other)
@@ -186,9 +195,16 @@
event = std::move(other.event);
source = std::move(other.source);
prepare = std::move(other.prepare);
+
+ set_userdata();
}
return *this;
}
+void Base::set_userdata()
+{
+ event.getSdEvent()->sd_event_source_set_userdata(source.get(), this);
+}
+
} // namespace source
} // namespace sdeventplus
diff --git a/src/sdeventplus/source/base.hpp b/src/sdeventplus/source/base.hpp
index d576b24..ed30016 100644
--- a/src/sdeventplus/source/base.hpp
+++ b/src/sdeventplus/source/base.hpp
@@ -47,11 +47,13 @@
Base(const Base& other) = delete;
Base& operator=(const Base& other) = delete;
// We don't want to allow any kind of slicing.
- Base(Base&& other) = default;
+ Base(Base&& other);
Base& operator=(Base&& other);
private:
Callback prepare;
+
+ void set_userdata();
};
} // namespace source
diff --git a/src/sdeventplus/test/sdevent.hpp b/src/sdeventplus/test/sdevent.hpp
index fd05b30..9b39d50 100644
--- a/src/sdeventplus/test/sdevent.hpp
+++ b/src/sdeventplus/test/sdevent.hpp
@@ -34,6 +34,9 @@
MOCK_CONST_METHOD1(sd_event_source_unref,
sd_event_source*(sd_event_source*));
+ MOCK_CONST_METHOD2(sd_event_source_set_userdata,
+ void*(sd_event_source*, void*));
+
MOCK_CONST_METHOD2(sd_event_source_get_description,
int(sd_event_source*, const char**));
MOCK_CONST_METHOD2(sd_event_source_set_description,
diff --git a/test/source/base.cpp b/test/source/base.cpp
index 0ca093b..69ae8e2 100644
--- a/test/source/base.cpp
+++ b/test/source/base.cpp
@@ -65,7 +65,11 @@
{
EXPECT_CALL(mock, sd_event_ref(event.get()))
.WillOnce(Return(event.get()));
+ void* userdata;
+ EXPECT_CALL(mock, sd_event_source_set_userdata(source, testing::_))
+ .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
auto ret = std::make_unique<BaseImpl>(event, source, std::false_type());
+ EXPECT_EQ(ret.get(), userdata);
EXPECT_EQ(source, ret->get());
EXPECT_NE(&event, &ret->get_event());
EXPECT_EQ(event.get(), ret->get_event().get());
@@ -83,7 +87,11 @@
void empty_base(BaseImpl&& other)
{
+ void* userdata;
+ EXPECT_CALL(mock, sd_event_source_set_userdata(other.get(), testing::_))
+ .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
BaseImpl mover(std::move(other));
+ EXPECT_EQ(&mover, userdata);
EXPECT_EQ(nullptr, other.get());
EXPECT_EQ(nullptr, other.get_event().get());
EXPECT_FALSE(other.get_prepare());
@@ -111,7 +119,11 @@
.WillOnce(Return(expected_event));
EXPECT_CALL(mock, sd_event_source_ref(expected_source))
.WillOnce(Return(expected_source));
+ void* userdata;
+ EXPECT_CALL(mock, sd_event_source_set_userdata(expected_source, testing::_))
+ .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
BaseImpl source(*event, expected_source);
+ EXPECT_EQ(&source, userdata);
EXPECT_EQ(expected_source, source.get());
EXPECT_NE(event.get(), &source.get_event());
EXPECT_EQ(expected_event, source.get_event().get());
@@ -124,7 +136,11 @@
{
EXPECT_CALL(mock, sd_event_ref(expected_event))
.WillOnce(Return(expected_event));
+ void* userdata;
+ EXPECT_CALL(mock, sd_event_source_set_userdata(expected_source, testing::_))
+ .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
BaseImpl source(*event, expected_source, std::false_type());
+ EXPECT_EQ(&source, userdata);
EXPECT_EQ(expected_source, source.get());
EXPECT_NE(event.get(), &source.get_event());
EXPECT_EQ(expected_event, source.get_event().get());
@@ -138,7 +154,11 @@
std::unique_ptr<BaseImpl> source1 = make_base(*event, expected_source);
set_prepare_placeholder(*source1);
+ void* userdata;
+ EXPECT_CALL(mock, sd_event_source_set_userdata(expected_source, testing::_))
+ .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
BaseImpl source2(std::move(*source1));
+ EXPECT_EQ(&source2, userdata);
EXPECT_EQ(nullptr, source1->get());
EXPECT_EQ(nullptr, source1->get_event().get());
EXPECT_FALSE(source1->get_prepare());
@@ -171,8 +191,12 @@
empty_base(std::move(*source2));
{
- testing::InSequence seq;
+ void* userdata;
+ EXPECT_CALL(mock,
+ sd_event_source_set_userdata(expected_source, testing::_))
+ .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
*source2 = std::move(*source1);
+ EXPECT_EQ(source2.get(), userdata);
}
EXPECT_EQ(nullptr, source1->get());
EXPECT_EQ(nullptr, source1->get_event().get());
@@ -200,7 +224,12 @@
{
expect_base_destruct(*event2, expected_source2);
+ void* userdata;
+ EXPECT_CALL(mock,
+ sd_event_source_set_userdata(expected_source, testing::_))
+ .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
*source2 = std::move(*source1);
+ EXPECT_EQ(source2.get(), userdata);
}
EXPECT_EQ(nullptr, source1->get());
EXPECT_EQ(nullptr, source1->get_event().get());