diff --git a/src/Connection.cpp b/src/Connection.cpp index 5d09392..a11a4c6 100644 --- a/src/Connection.cpp +++ b/src/Connection.cpp @@ -190,6 +190,17 @@ SlotPtr Connection::addObjectVTable( const std::string& objectPath return {slot, [this](void *slot){ iface_->sd_bus_slot_unref((sd_bus_slot*)slot); }}; } +PlainMessage Connection::createPlainMessage() const +{ + sd_bus_message* sdbusMsg{}; + + auto r = iface_->sd_bus_message_new(bus_.get(), &sdbusMsg, _SD_BUS_MESSAGE_TYPE_INVALID); + + SDBUS_THROW_ERROR_IF(r < 0, "Failed to create a plain message", -r); + + return Message::Factory::create(sdbusMsg, iface_.get(), adopt_message); +} + MethodCall Connection::createMethodCall( const std::string& destination , const std::string& objectPath , const std::string& interfaceName @@ -213,17 +224,17 @@ Signal Connection::createSignal( const std::string& objectPath , const std::string& interfaceName , const std::string& signalName ) const { - sd_bus_message *sdbusSignal{}; + sd_bus_message *sdbusMsg{}; auto r = iface_->sd_bus_message_new_signal( bus_.get() - , &sdbusSignal + , &sdbusMsg , objectPath.c_str() , interfaceName.c_str() , signalName.c_str() ); SDBUS_THROW_ERROR_IF(r < 0, "Failed to create signal", -r); - return Message::Factory::create(sdbusSignal, iface_.get(), adopt_message); + return Message::Factory::create(sdbusMsg, iface_.get(), adopt_message); } void Connection::emitPropertiesChangedSignal( const std::string& objectPath @@ -447,6 +458,16 @@ Connection::LoopExitEventFd::~LoopExitEventFd() namespace sdbus { +namespace internal { +std::unique_ptr createConnection() +{ + auto connection = sdbus::createConnection(); + SCOPE_EXIT{ connection.release(); }; + auto connectionInternal = dynamic_cast(connection.get()); + return std::unique_ptr(connectionInternal); +} +} + std::unique_ptr createConnection() { return createSystemBusConnection(); diff --git a/src/Connection.h b/src/Connection.h index 2fa5f90..b374290 100644 --- a/src/Connection.h +++ b/src/Connection.h @@ -80,11 +80,11 @@ namespace sdbus { namespace internal { , const sd_bus_vtable* vtable , void* userData ) override; + PlainMessage createPlainMessage() const override; MethodCall createMethodCall( const std::string& destination , const std::string& objectPath , const std::string& interfaceName , const std::string& methodName ) const override; - Signal createSignal( const std::string& objectPath , const std::string& interfaceName , const std::string& signalName ) const override; diff --git a/src/IConnection.h b/src/IConnection.h index 549f735..a0d289f 100644 --- a/src/IConnection.h +++ b/src/IConnection.h @@ -38,6 +38,7 @@ namespace sdbus { class MethodCall; class MethodReply; class Signal; + class PlainMessage; namespace internal { class ISdBus; } @@ -61,11 +62,11 @@ namespace internal { , const sd_bus_vtable* vtable , void* userData ) = 0; + virtual PlainMessage createPlainMessage() const = 0; virtual MethodCall createMethodCall( const std::string& destination , const std::string& objectPath , const std::string& interfaceName , const std::string& methodName ) const = 0; - virtual Signal createSignal( const std::string& objectPath , const std::string& interfaceName , const std::string& signalName ) const = 0; @@ -94,6 +95,8 @@ namespace internal { virtual MethodReply tryCallMethodSynchronously(const MethodCall& message, uint64_t timeout) = 0; }; + std::unique_ptr createConnection(); + } } diff --git a/src/ISdBus.h b/src/ISdBus.h index 7246b4f..a5dc994 100644 --- a/src/ISdBus.h +++ b/src/ISdBus.h @@ -51,6 +51,7 @@ namespace sdbus { namespace internal { virtual int sd_bus_call(sd_bus *bus, sd_bus_message *m, uint64_t usec, sd_bus_error *ret_error, sd_bus_message **reply) = 0; virtual int sd_bus_call_async(sd_bus *bus, sd_bus_slot **slot, sd_bus_message *m, sd_bus_message_handler_t callback, void *userdata, uint64_t usec) = 0; + virtual int sd_bus_message_new(sd_bus *bus, sd_bus_message **m, uint8_t type) = 0; virtual int sd_bus_message_new_method_call(sd_bus *bus, sd_bus_message **m, const char *destination, const char *path, const char *interface, const char *member) = 0; virtual int sd_bus_message_new_signal(sd_bus *bus, sd_bus_message **m, const char *path, const char *interface, const char *member) = 0; virtual int sd_bus_message_new_method_return(sd_bus_message *call, sd_bus_message **m) = 0; diff --git a/src/Message.cpp b/src/Message.cpp index 6356fd4..4c99541 100644 --- a/src/Message.cpp +++ b/src/Message.cpp @@ -28,7 +28,8 @@ #include #include #include "MessageUtils.h" -#include "SdBus.h" +#include "ISdBus.h" +#include "IConnection.h" #include "ScopeGuard.h" #include #include @@ -712,60 +713,8 @@ void Signal::send() const PlainMessage createPlainMessage() { - int r; - - // All references to the bus (like created messages) must not outlive this thread (because messages refer to sdbus - // which is thread-local, and because BusReferenceKeeper below destroys the bus at thread exit). - // A more flexible solution would be that the caller would already provide an ISdBus reference as a parameter. - // Variant is one of the callers. This means Variant could no more be created in a stand-alone way, but - // through a factory of some existing facility (Object, Proxy, Connection...). - // TODO: Consider this alternative of creating Variant, it may live next to the current one. This function would - // get IConnection* parameter and IConnection would provide createPlainMessage factory (just like it already - // provides e.g. createMethodCall). If this parameter were null, the current mechanism would be used. - - thread_local internal::SdBus sdbus; - - sd_bus* bus{}; - SCOPE_EXIT{ sd_bus_unref(bus); }; - r = sd_bus_default_system(&bus); - SDBUS_THROW_ERROR_IF(r < 0, "Failed to get default system bus", -r); - - thread_local struct BusReferenceKeeper - { - explicit BusReferenceKeeper(sd_bus* bus) : bus_(sd_bus_ref(bus)) { sd_bus_flush(bus_); } - ~BusReferenceKeeper() { sd_bus_flush_close_unref(bus_); } - sd_bus* bus_{}; - } busReferenceKeeper{bus}; - -// thread_local struct BusKeeper -// { -// BusKeeper() -// { -// auto r = sd_bus_open_system(&bus); -// sd_bus_flush(bus); -// SDBUS_THROW_ERROR_IF(r < 0, "Failed to get default system bus", -r); -// } - -// ~BusKeeper() -// { -// sd_bus_flush_close_unref(bus); -// } - -// sd_bus* bus{}; -// internal::SdBus intf; -// } busKeeper; - - // Shelved here as handy thing for potential future tracing purposes: - //#include - //#include - //#define gettid() syscall(SYS_gettid) - //printf("createPlainMessage: sd_bus*=[%p], n_ref=[%d], TID=[%d]\n", bus, *(unsigned*)bus, gettid()); - - sd_bus_message* sdbusMsg{}; - r = sd_bus_message_new(bus, &sdbusMsg, _SD_BUS_MESSAGE_TYPE_INVALID); - SDBUS_THROW_ERROR_IF(r < 0, "Failed to create a new message", -r); - - return Message::Factory::create(sdbusMsg, &sdbus, adopt_message); + static auto connection = internal::createConnection(); + return connection->createPlainMessage(); } } diff --git a/src/SdBus.cpp b/src/SdBus.cpp index a2f97b5..5acee87 100644 --- a/src/SdBus.cpp +++ b/src/SdBus.cpp @@ -65,6 +65,13 @@ int SdBus::sd_bus_call_async(sd_bus *bus, sd_bus_slot **slot, sd_bus_message *m, return ::sd_bus_call_async(bus, slot, m, callback, userdata, usec); } +int SdBus::sd_bus_message_new(sd_bus *bus, sd_bus_message **m, uint8_t type) +{ + std::unique_lock lock(sdbusMutex_); + + return ::sd_bus_message_new(bus, m, type); +} + int SdBus::sd_bus_message_new_method_call(sd_bus *bus, sd_bus_message **m, const char *destination, const char *path, const char *interface, const char *member) { std::unique_lock lock(sdbusMutex_); diff --git a/src/SdBus.h b/src/SdBus.h index 3ab28c2..ef8d461 100644 --- a/src/SdBus.h +++ b/src/SdBus.h @@ -43,6 +43,7 @@ public: virtual int sd_bus_call(sd_bus *bus, sd_bus_message *m, uint64_t usec, sd_bus_error *ret_error, sd_bus_message **reply) override; virtual int sd_bus_call_async(sd_bus *bus, sd_bus_slot **slot, sd_bus_message *m, sd_bus_message_handler_t callback, void *userdata, uint64_t usec) override; + virtual int sd_bus_message_new(sd_bus *bus, sd_bus_message **m, uint8_t type) override; virtual int sd_bus_message_new_method_call(sd_bus *bus, sd_bus_message **m, const char *destination, const char *path, const char *interface, const char *member) override; virtual int sd_bus_message_new_signal(sd_bus *bus, sd_bus_message **m, const char *path, const char *interface, const char *member) override; virtual int sd_bus_message_new_method_return(sd_bus_message *call, sd_bus_message **m) override; diff --git a/tests/unittests/mocks/SdBusMock.h b/tests/unittests/mocks/SdBusMock.h index 468e0be..2a81118 100644 --- a/tests/unittests/mocks/SdBusMock.h +++ b/tests/unittests/mocks/SdBusMock.h @@ -42,6 +42,7 @@ public: MOCK_METHOD5(sd_bus_call, int(sd_bus *bus, sd_bus_message *m, uint64_t usec, sd_bus_error *ret_error, sd_bus_message **reply)); MOCK_METHOD6(sd_bus_call_async, int(sd_bus *bus, sd_bus_slot **slot, sd_bus_message *m, sd_bus_message_handler_t callback, void *userdata, uint64_t usec)); + MOCK_METHOD3(sd_bus_message_new, int(sd_bus *bus, sd_bus_message **m, uint8_t type)); MOCK_METHOD6(sd_bus_message_new_method_call, int(sd_bus *bus, sd_bus_message **m, const char *destination, const char *path, const char *interface, const char *member)); MOCK_METHOD5(sd_bus_message_new_signal, int(sd_bus *bus, sd_bus_message **m, const char *path, const char *interface, const char *member)); MOCK_METHOD2(sd_bus_message_new_method_return, int(sd_bus_message *call, sd_bus_message **m));