bus: change constructor semantics
Previously, the bus object had no semantics to recognize if
it was the primary-holder of a sd_bus or a secondary one.
On destruction, the object always called 'sd_bus_unref' and it
was assumed that the sd-bus library would properly close the
bus on last-unref. This turns out not to be true and lead to
file-descriptor leaks.
Change the constructor to mimic what is done in 'message':
- When the constructor is called with a sd_bus*, the class becomes
a secondary-holder and calls 'sd_bus_unref' on destruction, which
is the old behavior. The class also calls 'sd_bus_ref' on
construction, so this should no longer be done by callers.
- When the constructor is called via the new_* functions (or by
adding a std::false_type parameter), the class becomes a primary-
holder and calls 'sd_bus_flush_close_unref' on destruction.
Note: Current callers that use syntax like 'bus(sd_bus_ref(b))' will
need to be updated to avoid a file-descriptor leak.
Fixes openbmc/openbmc#1432.
Change-Id: Ic0c582f8fbfd44775bcdaffa6a21518a0cd056b1
Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
diff --git a/sdbusplus/bus.hpp.in b/sdbusplus/bus.hpp.in
index 94d5588..185ffd7 100644
--- a/sdbusplus/bus.hpp.in
+++ b/sdbusplus/bus.hpp.in
@@ -36,8 +36,10 @@
{
void operator()(sd_bus* ptr) const
{
- sd_bus_unref(ptr);
+ deleter(ptr);
}
+
+ decltype(&sd_bus_flush_close_unref) deleter = sd_bus_flush_close_unref;
};
/* @brief Alias 'bus' to a unique_ptr type for auto-release. */
@@ -67,10 +69,18 @@
/** @brief Conversion constructor from 'busp_t'.
*
- * Takes ownership of the bus-pointer and releases it when done.
+ * Increments ref-count of the bus-pointer and releases it when done.
*/
explicit bus(busp_t b);
+ /** @brief Constructor for 'bus'.
+ *
+ * Takes ownership of the bus-pointer and releases it when done.
+ * This method will also cause the bus to be flushed and closed
+ * on destruction.
+ */
+ bus(busp_t b, std::false_type);
+
/** @brief Release ownership of the stored bus-pointer. */
busp_t release() { return _bus.release(); }
@@ -237,7 +247,24 @@
details::bus _bus;
};
-inline bus::bus(busp_t b) : _bus(b)
+inline bus::bus(busp_t b) : _bus(sd_bus_ref(b))
+{
+ _bus.get_deleter().deleter = sd_bus_unref;
+
+#if @WANT_TRANSACTION@
+ // Emitting object added causes a message to get the properties
+ // which can trigger a 'transaction' in the server bindings. If
+ // the bus isn't up far enough, this causes an assert deep in
+ // sd-bus code. Get the 'unique_name' to ensure the bus is up far
+ // enough to avoid the assert.
+ if (b != nullptr)
+ {
+ get_unique_name();
+ }
+#endif
+}
+
+inline bus::bus(busp_t b, std::false_type) : _bus(b)
{
#if @WANT_TRANSACTION@
// Emitting object added causes a message to get the properties
@@ -257,21 +284,21 @@
{
sd_bus* b = nullptr;
sd_bus_open(&b);
- return bus(b);
+ return bus(b, std::false_type());
}
inline bus new_user()
{
sd_bus* b = nullptr;
sd_bus_open_user(&b);
- return bus(b);
+ return bus(b, std::false_type());
}
inline bus new_system()
{
sd_bus* b = nullptr;
sd_bus_open_system(&b);
- return bus(b);
+ return bus(b, std::false_type());
}
} // namespace bus
@@ -284,7 +311,7 @@
{
sd_bus* b = nullptr;
b = sd_bus_message_get_bus(_msg.get());
- return bus::bus(sd_bus_ref(b));
+ return bus::bus(b);
}
} // namespace sdbusplus