diff --git a/README.md b/README.md index f13ea20..b4dd080 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ $ sudo make install * `LIBSYSTEMD_VERSION` [string] - Defines version of systemd to be downloaded, built and integrated into sdbus-c++. Default value: `v239`. + Defines version of systemd to be downloaded, built and integrated into sdbus-c++. Default value: `242`. * `CMAKE_BUILD_TYPE` [string] diff --git a/cmake/LibsystemdExternalProject.cmake b/cmake/LibsystemdExternalProject.cmake index 956fca2..5a0ce16 100644 --- a/cmake/LibsystemdExternalProject.cmake +++ b/cmake/LibsystemdExternalProject.cmake @@ -7,13 +7,12 @@ endif() find_library(GLIBC_RT_LIBRARY rt) find_package(PkgConfig REQUIRED) -pkg_check_modules(MOUNT REQUIRED mount) pkg_check_modules(CAP REQUIRED libcap) if (NOT CAP_FOUND) find_library(CAP_LIBRARIES cap) # Compat with Ubuntu 14.04 which ships libcap w/o .pc file endif() -set(LIBSYSTEMD_VERSION v239 CACHE STRING "libsystemd version (>=v239) to build and incorporate into libsdbus-c++") +set(LIBSYSTEMD_VERSION "242" CACHE STRING "libsystemd version (>=239) to build and incorporate into libsdbus-c++") if(NOT CMAKE_BUILD_TYPE) set(LIBSYSTEMD_BUILD_TYPE "plain") @@ -23,15 +22,23 @@ else() set(LIBSYSTEMD_BUILD_TYPE "release") endif() +if(LIBSYSTEMD_VERSION LESS "239") + message(FATAL_ERROR "Only libsystemd version >=239 can be built as static part of sdbus-c++") +endif() +if(LIBSYSTEMD_VERSION GREATER "240") + set(BUILD_VERSION_H ${NINJA} -C version.h) +endif() + include(ExternalProject) ExternalProject_Add(LibsystemdBuildProject - PREFIX libsystemd + PREFIX libsystemd-v${LIBSYSTEMD_VERSION} GIT_REPOSITORY https://github.com/systemd/systemd.git - GIT_TAG ${LIBSYSTEMD_VERSION} + GIT_TAG v${LIBSYSTEMD_VERSION} UPDATE_COMMAND "" CONFIGURE_COMMAND ${CMAKE_COMMAND} -E remove /* COMMAND ${MESON} --buildtype=${LIBSYSTEMD_BUILD_TYPE} -Dstatic-libsystemd=pic - BUILD_COMMAND ${NINJA} -C libsystemd.a + BUILD_COMMAND ${BUILD_VERSION_H} + COMMAND ${NINJA} -C libsystemd.a INSTALL_COMMAND "" LOG_DOWNLOAD 1 LOG_UPDATE 1 LOG_CONFIGURE 1 LOG_BUILD 1) @@ -40,7 +47,6 @@ set(SYSTEMD_INCLUDE_DIRS ${SOURCE_DIR}/src) ExternalProject_Get_property(LibsystemdBuildProject BINARY_DIR) set(SYSTEMD_LIBRARY_DIRS ${BINARY_DIR}) -#add_library(libsystemd-static STATIC IMPORTED) -#set_target_properties(libsystemd-static PROPERTIES IMPORTED_LOCATION ${SYSTEMD_LIBRARY_DIRS}/libsystemd.a) -#target_link_libraries(libsystemd-static ${MOUNT_LIBRARIES} ${CAP_LIBRARIES} ${GLIBC_RT_LIBRARY}) -set(SYSTEMD_LIBRARIES ${SYSTEMD_LIBRARY_DIRS}/libsystemd.a ${MOUNT_LIBRARIES} ${CAP_LIBRARIES} ${GLIBC_RT_LIBRARY}) +add_library(libsystemd-static STATIC IMPORTED) +set_target_properties(libsystemd-static PROPERTIES IMPORTED_LOCATION ${SYSTEMD_LIBRARY_DIRS}/libsystemd.a) +set(SYSTEMD_LIBRARIES libsystemd-static ${CAP_LIBRARIES} ${GLIBC_RT_LIBRARY}) diff --git a/docs/using-sdbus-c++.md b/docs/using-sdbus-c++.md index 3af1b33..0193471 100644 --- a/docs/using-sdbus-c++.md +++ b/docs/using-sdbus-c++.md @@ -75,9 +75,9 @@ $ ninja libsystemd.so.0.26.0 # or another version number depending which system ### Building and distributing libsystemd as part of sdbus-c++ -sdbus-c++ provides `BUILD_LIBSYSTEMD` configuration option. When turned on, sdbus-c++ will automatically download, build and integrate libsystemd as a static library into sdbus-c++ for you. This is the most convenient and effective approach to build, distribute and use sdbus-c++ as a self-contained, systemd-independent library in non-systemd enviroments. Just make sure your build machine has all dependencies needed by libsystemd build process. That includes `meson`, `ninja`, `git` programs and mainly libraries and headers for `libmount`, `libcap` and `librt` (part of glibc). Also when distributing, make sure these dependency libraries are installed on the production machine. (Contributors willing to help with bringing sdbus-c++ to popular package systems are welcome.) +sdbus-c++ provides `BUILD_LIBSYSTEMD` configuration option. When turned on, sdbus-c++ will automatically download, build and integrate libsystemd as a static library into sdbus-c++ for you. This is the most convenient and effective approach to build, distribute and use sdbus-c++ as a self-contained, systemd-independent library in non-systemd enviroments. Just make sure your build machine has all dependencies needed by libsystemd build process. That includes `meson`, `ninja`, `git` programs and mainly libraries and library headers for `libmount`, `libcap` and `librt` (part of glibc). Also when distributing, make sure these dependency libraries are installed on the production machine. (Contributors willing to help with bringing sdbus-c++ to popular package systems are welcome.) -You may additionally use `LIBSYSTEMD_VERSION` configuration flag to fine-tune the version of systemd to be taken in. +You may additionally set the `LIBSYSTEMD_VERSION` configuration flag to fine-tune the version of systemd to be taken in. (The default value is 242). Header files and namespaces --------------------------- diff --git a/src/Message.cpp b/src/Message.cpp index 2ba7bf8..582f696 100644 --- a/src/Message.cpp +++ b/src/Message.cpp @@ -684,6 +684,17 @@ Message 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); @@ -691,17 +702,37 @@ Message createPlainMessage() thread_local struct BusReferenceKeeper { - BusReferenceKeeper(sd_bus* bus) : bus_(bus) {} - ~BusReferenceKeeper() { sd_bus_unref(bus_); } + BusReferenceKeeper(sd_bus* bus) : bus_(sd_bus_ref(bus)) + { + // Try to finish all the handshake, receive HELLO msg reply and set the bus to running state + sd_bus_flush(bus_); + } + + ~BusReferenceKeeper() + { + // Yeah, this is kind of defensive, one sd_bus_unref should normally suffice, but I'm not sure whether + // all pending references to the bus have been resolved by now (like internal sd-bus HELLO messages, + // even though I use sd_bus_flush above), and sd-bus of systemd v242 has slightly different ref counting + // behavior here... So I better be more defensive rather than cause memory leaks in some special cases... + // And anyway, there should be no user's messages with reference to this bus hanging around at this point + // (see comment above), so it's safe to go all the way down to zero ref count and free the bus. + while (sd_bus_default_system(nullptr)) + sd_bus_unref(bus_); + } + sd_bus* bus_{}; } busReferenceKeeper{bus}; + // 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); - thread_local internal::SdBus sdbus; - return Message{sdbusMsg, &sdbus, adopt_message}; }