mirror of
https://github.com/Kistler-Group/sdbus-cpp.git
synced 2025-08-03 03:54:27 +02:00
WIP
This commit is contained in:
@@ -13,7 +13,9 @@ include(GNUInstallDirs) # Installation directories for `install` command and pkg
|
|||||||
#-------------------------------
|
#-------------------------------
|
||||||
|
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(PkgConfig REQUIRED)
|
||||||
pkg_check_modules(SYSTEMD REQUIRED libsystemd>=236)
|
#pkg_check_modules(SYSTEMD REQUIRED libsystemd>=236)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_FLAGS "-O0 -g")
|
||||||
|
|
||||||
#-------------------------------
|
#-------------------------------
|
||||||
# SOURCE FILES CONFIGURATION
|
# SOURCE FILES CONFIGURATION
|
||||||
@@ -80,7 +82,7 @@ set(SDBUSCPP_VERSION "${PROJECT_VERSION}")
|
|||||||
# We are building in two steps: first objects, then link them into a library,
|
# We are building in two steps: first objects, then link them into a library,
|
||||||
# and that's because we need object files since unit tests link against them.
|
# and that's because we need object files since unit tests link against them.
|
||||||
add_library(sdbuscppobjects OBJECT ${SDBUSCPP_SRCS})
|
add_library(sdbuscppobjects OBJECT ${SDBUSCPP_SRCS})
|
||||||
target_include_directories(sdbuscppobjects PUBLIC ${SYSTEMD_INCLUDE_DIRS})
|
#target_include_directories(sdbuscppobjects PUBLIC ${SYSTEMD_INCLUDE_DIRS})
|
||||||
target_compile_definitions(sdbuscppobjects PRIVATE BUILDLIB=1)
|
target_compile_definitions(sdbuscppobjects PRIVATE BUILDLIB=1)
|
||||||
set_target_properties(sdbuscppobjects PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
set_target_properties(sdbuscppobjects PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||||
|
|
||||||
@@ -91,7 +93,7 @@ set_target_properties(sdbus-c++
|
|||||||
VERSION "${SDBUSCPP_VERSION}"
|
VERSION "${SDBUSCPP_VERSION}"
|
||||||
SOVERSION "${SDBUSCPP_VERSION_MAJOR}"
|
SOVERSION "${SDBUSCPP_VERSION_MAJOR}"
|
||||||
OUTPUT_NAME "sdbus-c++")
|
OUTPUT_NAME "sdbus-c++")
|
||||||
target_link_libraries(sdbus-c++ ${SYSTEMD_LIBRARIES})
|
target_link_libraries(sdbus-c++ -L/home/aeywalee/data/repos/systemd/.libs/ -lsystemd)
|
||||||
|
|
||||||
#----------------------------------
|
#----------------------------------
|
||||||
# INSTALLATION
|
# INSTALLATION
|
||||||
|
@@ -79,7 +79,7 @@ void Connection::enterProcessingLoop()
|
|||||||
if (!success)
|
if (!success)
|
||||||
break; // Exit processing loop
|
break; // Exit processing loop
|
||||||
if (success.asyncMsgsToProcess)
|
if (success.asyncMsgsToProcess)
|
||||||
processAsynchronousMessages();
|
processUserRequests();
|
||||||
}
|
}
|
||||||
|
|
||||||
loopThreadId_ = std::thread::id{};
|
loopThreadId_ = std::thread::id{};
|
||||||
@@ -122,10 +122,10 @@ void Connection::removeObjectVTable(void* vtableHandle)
|
|||||||
sd_bus_slot_unref((sd_bus_slot *)vtableHandle);
|
sd_bus_slot_unref((sd_bus_slot *)vtableHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
sdbus::MethodCall Connection::createMethodCall( const std::string& destination
|
MethodCall Connection::createMethodCall( const std::string& destination
|
||||||
, const std::string& objectPath
|
, const std::string& objectPath
|
||||||
, const std::string& interfaceName
|
, const std::string& interfaceName
|
||||||
, const std::string& methodName ) const
|
, const std::string& methodName ) const
|
||||||
{
|
{
|
||||||
sd_bus_message *sdbusMsg{};
|
sd_bus_message *sdbusMsg{};
|
||||||
|
|
||||||
@@ -145,44 +145,9 @@ sdbus::MethodCall Connection::createMethodCall( const std::string& destination
|
|||||||
return MethodCall(sdbusMsg);
|
return MethodCall(sdbusMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
sdbus::MethodReply Connection::callMethod(const MethodCall& message)
|
Signal Connection::createSignal( const std::string& objectPath
|
||||||
{
|
, const std::string& interfaceName
|
||||||
std::thread::id loopThreadId = loopThreadId_;
|
, const std::string& signalName ) const
|
||||||
|
|
||||||
// Is the loop not yet on? => Go make synchronous call
|
|
||||||
while (loopThreadId == std::thread::id{})
|
|
||||||
{
|
|
||||||
// Did the loop begin in the meantime? Or try_lock() failed spuriously?
|
|
||||||
if (!loopMutex_.try_lock())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Synchronous call
|
|
||||||
std::lock_guard<std::mutex> guard(loopMutex_, std::adopt_lock);
|
|
||||||
return message.send();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is the loop on and we are in the same thread? => Go for synchronous call
|
|
||||||
if (loopThreadId == std::this_thread::get_id())
|
|
||||||
{
|
|
||||||
assert(!loopMutex_.try_lock());
|
|
||||||
return message.send(); // Synchronous call
|
|
||||||
}
|
|
||||||
|
|
||||||
// We are in a different thread than the loop thread => Asynchronous call
|
|
||||||
UserRequest request{message, Message::Type::METHOD_CALL, {}, Message::Type::METHOD_REPLY};
|
|
||||||
auto future = request.ret.get_future();
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> guard(userRequestsMutex_);
|
|
||||||
userRequests_.push(request);
|
|
||||||
}
|
|
||||||
// Wait for the reply from the loop thread
|
|
||||||
auto reply = future.get();
|
|
||||||
return *static_cast<const MethodReply*>(&reply);
|
|
||||||
}
|
|
||||||
|
|
||||||
sdbus::Signal Connection::createSignal( const std::string& objectPath
|
|
||||||
, const std::string& interfaceName
|
|
||||||
, const std::string& signalName ) const
|
|
||||||
{
|
{
|
||||||
sd_bus_message *sdbusSignal{};
|
sd_bus_message *sdbusSignal{};
|
||||||
|
|
||||||
@@ -207,14 +172,61 @@ void* Connection::registerSignalHandler( const std::string& objectPath
|
|||||||
, sd_bus_message_handler_t callback
|
, sd_bus_message_handler_t callback
|
||||||
, void* userData )
|
, void* userData )
|
||||||
{
|
{
|
||||||
sd_bus_slot *slot{};
|
auto registerSignalHandler = [this]( const std::string& objectPath
|
||||||
|
, const std::string& interfaceName
|
||||||
|
, const std::string& signalName
|
||||||
|
, sd_bus_message_handler_t callback
|
||||||
|
, void* userData )
|
||||||
|
{
|
||||||
|
sd_bus_slot *slot{};
|
||||||
|
|
||||||
auto filter = composeSignalMatchFilter(objectPath, interfaceName, signalName);
|
auto filter = composeSignalMatchFilter(objectPath, interfaceName, signalName);
|
||||||
auto r = sd_bus_add_match(bus_.get(), &slot, filter.c_str(), callback, userData);
|
auto r = sd_bus_add_match(bus_.get(), &slot, filter.c_str(), callback, userData);
|
||||||
|
|
||||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to register signal handler", -r);
|
SDBUS_THROW_ERROR_IF(r < 0, "Failed to register signal handler", -r);
|
||||||
|
|
||||||
return slot;
|
return slot;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::thread::id loopThreadId = loopThreadId_;
|
||||||
|
|
||||||
|
// Is the loop not yet on? => Go make synchronous call
|
||||||
|
while (loopThreadId == std::thread::id{})
|
||||||
|
{
|
||||||
|
// Did the loop begin in the meantime? Or try_lock() failed spuriously?
|
||||||
|
if (!loopMutex_.try_lock())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Synchronous call
|
||||||
|
std::lock_guard<std::mutex> guard(loopMutex_, std::adopt_lock);
|
||||||
|
return registerSignalHandler(objectPath, interfaceName, signalName, callback, userData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is the loop on and we are in the same thread? => Go for synchronous call
|
||||||
|
if (loopThreadId == std::this_thread::get_id())
|
||||||
|
{
|
||||||
|
assert(!loopMutex_.try_lock());
|
||||||
|
return registerSignalHandler(objectPath, interfaceName, signalName, callback, userData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We are in a different thread than the loop thread => Asynchronous call
|
||||||
|
std::promise<void*> result;
|
||||||
|
auto future = result.get_future();
|
||||||
|
queueUserRequest([registerSignalHandler, objectPath, interfaceName, signalName, callback, userData, &result]()
|
||||||
|
{
|
||||||
|
SCOPE_EXIT_NAMED(onSdbusError){ result.set_exception(std::current_exception()); };
|
||||||
|
|
||||||
|
void* slot = registerSignalHandler(objectPath, interfaceName, signalName, callback, userData);
|
||||||
|
result.set_value(slot);
|
||||||
|
|
||||||
|
onSdbusError.dismiss();
|
||||||
|
});
|
||||||
|
auto request = std::make_unique<SignalRegistrationRequest>();
|
||||||
|
request->registerSignalHandler = registerSignalHandler;
|
||||||
|
auto future = request->result.get_future();
|
||||||
|
queueUserRequest(std::move(request));
|
||||||
|
// Wait for the reply from the loop thread
|
||||||
|
return future.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::unregisterSignalHandler(void* handlerCookie)
|
void Connection::unregisterSignalHandler(void* handlerCookie)
|
||||||
@@ -222,11 +234,129 @@ void Connection::unregisterSignalHandler(void* handlerCookie)
|
|||||||
sd_bus_slot_unref((sd_bus_slot *)handlerCookie);
|
sd_bus_slot_unref((sd_bus_slot *)handlerCookie);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::sendReplyAsynchronously(const sdbus::MethodReply& reply)
|
//class AsyncExecutor
|
||||||
|
//ifPossibleExecuteSync()
|
||||||
|
|
||||||
|
MethodReply Connection::callMethod(const MethodCall& message)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> guard(mutex_);
|
//ifPossibleExecuteSync().otherwiseExecuteAsync();
|
||||||
asyncReplies_.push(reply);
|
std::thread::id loopThreadId = loopThreadId_;
|
||||||
notifyProcessingLoop();
|
|
||||||
|
// Is the loop not yet on? => Go make synchronous call
|
||||||
|
while (loopThreadId == std::thread::id{})
|
||||||
|
{
|
||||||
|
// Did the loop begin in the meantime? Or try_lock() failed spuriously?
|
||||||
|
if (!loopMutex_.try_lock())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Synchronous call
|
||||||
|
std::lock_guard<std::mutex> guard(loopMutex_, std::adopt_lock);
|
||||||
|
return message.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is the loop on and we are in the same thread? => Go for synchronous call
|
||||||
|
if (loopThreadId == std::this_thread::get_id())
|
||||||
|
{
|
||||||
|
assert(!loopMutex_.try_lock());
|
||||||
|
return message.send(); // Synchronous call
|
||||||
|
}
|
||||||
|
|
||||||
|
// We are in a different thread than the loop thread => Asynchronous call
|
||||||
|
auto request = std::make_unique<MethodCallRequest>();
|
||||||
|
request->msg = message;
|
||||||
|
auto future = request->result.get_future();
|
||||||
|
queueUserRequest(std::move(request));
|
||||||
|
// Wait for the reply from the loop thread
|
||||||
|
return future.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Connection::callMethod(const AsyncMethodCall& message, void* callback, void* userData)
|
||||||
|
{
|
||||||
|
std::thread::id loopThreadId = loopThreadId_;
|
||||||
|
|
||||||
|
// Is the loop not yet on? => Go make synchronous call
|
||||||
|
while (loopThreadId == std::thread::id{})
|
||||||
|
{
|
||||||
|
// Did the loop begin in the meantime? Or try_lock() failed spuriously?
|
||||||
|
if (!loopMutex_.try_lock())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Synchronous call
|
||||||
|
std::lock_guard<std::mutex> guard(loopMutex_, std::adopt_lock);
|
||||||
|
return message.send(callback, userData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is the loop on and we are in the same thread? => Go for synchronous call
|
||||||
|
if (loopThreadId == std::this_thread::get_id())
|
||||||
|
{
|
||||||
|
assert(!loopMutex_.try_lock());
|
||||||
|
return message.send(callback, userData); // Synchronous call
|
||||||
|
}
|
||||||
|
|
||||||
|
// We are in a different thread than the loop thread => Asynchronous call
|
||||||
|
auto request = std::make_unique<AsyncMethodCallRequest>();
|
||||||
|
request->msg = message;
|
||||||
|
request->callback = callback;
|
||||||
|
request->userData = userData;
|
||||||
|
queueUserRequest(std::move(request));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Connection::sendMethodReply(const MethodReply& message)
|
||||||
|
{
|
||||||
|
std::thread::id loopThreadId = loopThreadId_;
|
||||||
|
|
||||||
|
// Is the loop not yet on? => Go make synchronous call
|
||||||
|
while (loopThreadId == std::thread::id{})
|
||||||
|
{
|
||||||
|
// Did the loop begin in the meantime? Or try_lock() failed spuriously?
|
||||||
|
if (!loopMutex_.try_lock())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Synchronous call
|
||||||
|
std::lock_guard<std::mutex> guard(loopMutex_, std::adopt_lock);
|
||||||
|
return message.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is the loop on and we are in the same thread? => Go for synchronous call
|
||||||
|
if (loopThreadId == std::this_thread::get_id())
|
||||||
|
{
|
||||||
|
assert(!loopMutex_.try_lock());
|
||||||
|
return message.send(); // Synchronous call
|
||||||
|
}
|
||||||
|
|
||||||
|
// We are in a different thread than the loop thread => Asynchronous call
|
||||||
|
auto request = std::make_unique<MethodReplyRequest>();
|
||||||
|
request->msg = message;
|
||||||
|
queueUserRequest(std::move(request));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Connection::emitSignal(const Signal& message)
|
||||||
|
{
|
||||||
|
std::thread::id loopThreadId = loopThreadId_;
|
||||||
|
|
||||||
|
// Is the loop not yet on? => Go make synchronous call
|
||||||
|
while (loopThreadId == std::thread::id{})
|
||||||
|
{
|
||||||
|
// Did the loop begin in the meantime? Or try_lock() failed spuriously?
|
||||||
|
if (!loopMutex_.try_lock())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Synchronous call
|
||||||
|
std::lock_guard<std::mutex> guard(loopMutex_, std::adopt_lock);
|
||||||
|
return message.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is the loop on and we are in the same thread? => Go for synchronous call
|
||||||
|
if (loopThreadId == std::this_thread::get_id())
|
||||||
|
{
|
||||||
|
assert(!loopMutex_.try_lock());
|
||||||
|
return message.send(); // Synchronous call
|
||||||
|
}
|
||||||
|
|
||||||
|
// We are in a different thread than the loop thread => Asynchronous call
|
||||||
|
auto request = std::make_unique<SignalEmissionRequest>();
|
||||||
|
request->msg = message;
|
||||||
|
queueUserRequest(std::move(request));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<sdbus::internal::IConnection> Connection::clone() const
|
std::unique_ptr<sdbus::internal::IConnection> Connection::clone() const
|
||||||
@@ -315,14 +445,23 @@ bool Connection::processPendingRequest()
|
|||||||
return r > 0;
|
return r > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::processAsynchronousMessages()
|
void Connection::queueUserRequest(std::unique_ptr<IUserRequest>&& request)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> guard(mutex_);
|
|
||||||
while (!asyncReplies_.empty())
|
|
||||||
{
|
{
|
||||||
auto reply = asyncReplies_.front();
|
std::lock_guard<std::mutex> guard(userRequestsMutex_);
|
||||||
asyncReplies_.pop();
|
userRequests_.push(std::move(request));
|
||||||
reply.send();
|
}
|
||||||
|
notifyProcessingLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Connection::processUserRequests()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> guard(userRequestsMutex_);
|
||||||
|
while (!userRequests_.empty())
|
||||||
|
{
|
||||||
|
auto& reply = userRequests_.front();
|
||||||
|
reply->process();
|
||||||
|
userRequests_.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
134
src/Connection.h
134
src/Connection.h
@@ -29,6 +29,7 @@
|
|||||||
#include <sdbus-c++/IConnection.h>
|
#include <sdbus-c++/IConnection.h>
|
||||||
#include <sdbus-c++/Message.h>
|
#include <sdbus-c++/Message.h>
|
||||||
#include "IConnection.h"
|
#include "IConnection.h"
|
||||||
|
#include "ScopeGuard.h"
|
||||||
#include <systemd/sd-bus.h>
|
#include <systemd/sd-bus.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
@@ -51,7 +52,7 @@ namespace sdbus { namespace internal {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Connection(BusType type);
|
Connection(BusType type);
|
||||||
~Connection();
|
~Connection() override;
|
||||||
|
|
||||||
void requestName(const std::string& name) override;
|
void requestName(const std::string& name) override;
|
||||||
void releaseName(const std::string& name) override;
|
void releaseName(const std::string& name) override;
|
||||||
@@ -65,13 +66,13 @@ namespace sdbus { namespace internal {
|
|||||||
, void* userData ) override;
|
, void* userData ) override;
|
||||||
void removeObjectVTable(void* vtableHandle) override;
|
void removeObjectVTable(void* vtableHandle) override;
|
||||||
|
|
||||||
sdbus::MethodCall createMethodCall( const std::string& destination
|
MethodCall createMethodCall( const std::string& destination
|
||||||
, const std::string& objectPath
|
, const std::string& objectPath
|
||||||
, const std::string& interfaceName
|
, const std::string& interfaceName
|
||||||
, const std::string& methodName ) const override;
|
, const std::string& methodName ) const override;
|
||||||
sdbus::Signal createSignal( const std::string& objectPath
|
Signal createSignal( const std::string& objectPath
|
||||||
, const std::string& interfaceName
|
, const std::string& interfaceName
|
||||||
, const std::string& signalName ) const override;
|
, const std::string& signalName ) const override;
|
||||||
|
|
||||||
void* registerSignalHandler( const std::string& objectPath
|
void* registerSignalHandler( const std::string& objectPath
|
||||||
, const std::string& interfaceName
|
, const std::string& interfaceName
|
||||||
@@ -80,8 +81,10 @@ namespace sdbus { namespace internal {
|
|||||||
, void* userData ) override;
|
, void* userData ) override;
|
||||||
void unregisterSignalHandler(void* handlerCookie) override;
|
void unregisterSignalHandler(void* handlerCookie) override;
|
||||||
|
|
||||||
MethodReply callMethod(const MethodCall& message);
|
MethodReply callMethod(const MethodCall& message) override;
|
||||||
void sendReplyAsynchronously(const sdbus::MethodReply& reply) override;
|
void callMethod(const AsyncMethodCall& message, void* callback, void* userData) override;
|
||||||
|
void sendMethodReply(const MethodReply& message) override;
|
||||||
|
void emitSignal(const Signal& message) override;
|
||||||
|
|
||||||
std::unique_ptr<sdbus::internal::IConnection> clone() const override;
|
std::unique_ptr<sdbus::internal::IConnection> clone() const override;
|
||||||
|
|
||||||
@@ -95,12 +98,106 @@ namespace sdbus { namespace internal {
|
|||||||
return msgsToProcess || asyncMsgsToProcess;
|
return msgsToProcess || asyncMsgsToProcess;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO move down
|
||||||
|
struct IUserRequest
|
||||||
|
{
|
||||||
|
virtual void process() = 0;
|
||||||
|
virtual ~IUserRequest() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MethodCallRequest : IUserRequest
|
||||||
|
{
|
||||||
|
MethodCall msg;
|
||||||
|
std::promise<MethodReply> result;
|
||||||
|
|
||||||
|
void process() override
|
||||||
|
{
|
||||||
|
SCOPE_EXIT_NAMED(onSdbusError){ result.set_exception(std::current_exception()); };
|
||||||
|
|
||||||
|
auto reply = msg.send();
|
||||||
|
result.set_value(std::move(reply));
|
||||||
|
|
||||||
|
onSdbusError.dismiss();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AsyncMethodCallRequest : IUserRequest
|
||||||
|
{
|
||||||
|
AsyncMethodCall msg;
|
||||||
|
void* callback;
|
||||||
|
void* userData;
|
||||||
|
|
||||||
|
// TODO: Catch exception and store to promise?
|
||||||
|
void process() override
|
||||||
|
{
|
||||||
|
msg.send(callback, userData);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MethodReplyRequest : IUserRequest
|
||||||
|
{
|
||||||
|
MethodReply msg;
|
||||||
|
|
||||||
|
// TODO: Catch exception and store to promise?
|
||||||
|
void process() override
|
||||||
|
{
|
||||||
|
msg.send();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SignalEmissionRequest : IUserRequest
|
||||||
|
{
|
||||||
|
Signal msg;
|
||||||
|
|
||||||
|
// TODO: Catch exception and store to promise?
|
||||||
|
void process() override
|
||||||
|
{
|
||||||
|
msg.send();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SignalRegistrationRequest : IUserRequest
|
||||||
|
{
|
||||||
|
std::function<void*()> registerSignalHandler;
|
||||||
|
std::promise<void*> result;
|
||||||
|
|
||||||
|
void process() override
|
||||||
|
{
|
||||||
|
SCOPE_EXIT_NAMED(onSdbusError){ result.set_exception(std::current_exception()); };
|
||||||
|
|
||||||
|
assert(registerSignalHandler);
|
||||||
|
void* slot = registerSignalHandler();
|
||||||
|
result.set_value(slot);
|
||||||
|
|
||||||
|
onSdbusError.dismiss();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SignalUnregistrationRequest : IUserRequest
|
||||||
|
{
|
||||||
|
std::function<void()> unregisterSignalHandler;
|
||||||
|
std::promise<void> result;
|
||||||
|
|
||||||
|
void process() override
|
||||||
|
{
|
||||||
|
SCOPE_EXIT_NAMED(onSdbusError){ result.set_exception(std::current_exception()); };
|
||||||
|
|
||||||
|
assert(unregisterSignalHandler);
|
||||||
|
unregisterSignalHandler();
|
||||||
|
result.set_value();
|
||||||
|
|
||||||
|
onSdbusError.dismiss();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static sd_bus* openBus(Connection::BusType type);
|
static sd_bus* openBus(Connection::BusType type);
|
||||||
static void finishHandshake(sd_bus* bus);
|
static void finishHandshake(sd_bus* bus);
|
||||||
static int createLoopNotificationDescriptor();
|
static int createLoopNotificationDescriptor();
|
||||||
static void closeLoopNotificationDescriptor(int fd);
|
static void closeLoopNotificationDescriptor(int fd);
|
||||||
bool processPendingRequest();
|
bool processPendingRequest();
|
||||||
void processAsynchronousMessages();
|
void queueUserRequest(std::unique_ptr<IUserRequest>&& request);
|
||||||
|
void processUserRequests();
|
||||||
WaitResult waitForNextRequest();
|
WaitResult waitForNextRequest();
|
||||||
static std::string composeSignalMatchFilter( const std::string& objectPath
|
static std::string composeSignalMatchFilter( const std::string& objectPath
|
||||||
, const std::string& interfaceName
|
, const std::string& interfaceName
|
||||||
@@ -115,20 +212,7 @@ namespace sdbus { namespace internal {
|
|||||||
std::atomic<std::thread::id> loopThreadId_;
|
std::atomic<std::thread::id> loopThreadId_;
|
||||||
std::mutex loopMutex_;
|
std::mutex loopMutex_;
|
||||||
|
|
||||||
//std::queue<MethodReply> asyncReplies_;
|
std::queue<std::unique_ptr<IUserRequest>> userRequests_;
|
||||||
struct UserRequest
|
|
||||||
{
|
|
||||||
Message msg;
|
|
||||||
Message::Type msgType;
|
|
||||||
std::promise<Message> ret;
|
|
||||||
Message::Type retType;
|
|
||||||
|
|
||||||
static_assert(sizeof(Message) == sizeof(MethodCall));
|
|
||||||
static_assert(sizeof(Message) == sizeof(AsyncMethodCall));
|
|
||||||
static_assert(sizeof(Message) == sizeof(MethodReply));
|
|
||||||
static_assert(sizeof(Message) == sizeof(Signal));
|
|
||||||
};
|
|
||||||
std::queue<UserRequest> userRequests_;
|
|
||||||
std::mutex userRequestsMutex_;
|
std::mutex userRequestsMutex_;
|
||||||
|
|
||||||
std::atomic<bool> exitLoopThread_;
|
std::atomic<bool> exitLoopThread_;
|
||||||
|
@@ -33,6 +33,7 @@
|
|||||||
// Forward declaration
|
// Forward declaration
|
||||||
namespace sdbus {
|
namespace sdbus {
|
||||||
class MethodCall;
|
class MethodCall;
|
||||||
|
class AsyncMethodCall;
|
||||||
class MethodReply;
|
class MethodReply;
|
||||||
class Signal;
|
class Signal;
|
||||||
}
|
}
|
||||||
@@ -49,14 +50,14 @@ namespace internal {
|
|||||||
, void* userData ) = 0;
|
, void* userData ) = 0;
|
||||||
virtual void removeObjectVTable(void* vtableHandle) = 0;
|
virtual void removeObjectVTable(void* vtableHandle) = 0;
|
||||||
|
|
||||||
virtual sdbus::MethodCall createMethodCall( const std::string& destination
|
virtual MethodCall createMethodCall( const std::string& destination
|
||||||
, const std::string& objectPath
|
, const std::string& objectPath
|
||||||
, const std::string& interfaceName
|
, const std::string& interfaceName
|
||||||
, const std::string& methodName ) const = 0;
|
, const std::string& methodName ) const = 0;
|
||||||
|
|
||||||
virtual sdbus::Signal createSignal( const std::string& objectPath
|
virtual Signal createSignal( const std::string& objectPath
|
||||||
, const std::string& interfaceName
|
, const std::string& interfaceName
|
||||||
, const std::string& signalName ) const = 0;
|
, const std::string& signalName ) const = 0;
|
||||||
|
|
||||||
virtual void* registerSignalHandler( const std::string& objectPath
|
virtual void* registerSignalHandler( const std::string& objectPath
|
||||||
, const std::string& interfaceName
|
, const std::string& interfaceName
|
||||||
@@ -68,7 +69,10 @@ namespace internal {
|
|||||||
virtual void enterProcessingLoopAsync() = 0;
|
virtual void enterProcessingLoopAsync() = 0;
|
||||||
virtual void leaveProcessingLoop() = 0;
|
virtual void leaveProcessingLoop() = 0;
|
||||||
|
|
||||||
virtual void sendReplyAsynchronously(const sdbus::MethodReply& reply) = 0;
|
virtual MethodReply callMethod(const MethodCall& message) = 0;
|
||||||
|
virtual void callMethod(const AsyncMethodCall& message, void* callback, void* userData) = 0;
|
||||||
|
virtual void sendMethodReply(const MethodReply& message) = 0;
|
||||||
|
virtual void emitSignal(const Signal& message) = 0;
|
||||||
|
|
||||||
virtual std::unique_ptr<sdbus::internal::IConnection> clone() const = 0;
|
virtual std::unique_ptr<sdbus::internal::IConnection> clone() const = 0;
|
||||||
|
|
||||||
|
@@ -37,7 +37,7 @@ MethodResult::MethodResult(const MethodCall& msg, sdbus::internal::Object& objec
|
|||||||
void MethodResult::send(const MethodReply& reply) const
|
void MethodResult::send(const MethodReply& reply) const
|
||||||
{
|
{
|
||||||
assert(object_ != nullptr);
|
assert(object_ != nullptr);
|
||||||
object_->sendReplyAsynchronously(reply);
|
object_->sendMethodReply(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -156,15 +156,12 @@ sdbus::Signal Object::createSignal(const std::string& interfaceName, const std::
|
|||||||
|
|
||||||
void Object::emitSignal(const sdbus::Signal& message)
|
void Object::emitSignal(const sdbus::Signal& message)
|
||||||
{
|
{
|
||||||
// TODO: Make signal emitting asynchronous. Now signal can probably be emitted only from user code
|
connection_.emitSignal(message);
|
||||||
// handled within the D-Bus processing loop thread, but not from any thread. In principle it will
|
|
||||||
// be the same as async replies.
|
|
||||||
message.send();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Object::sendReplyAsynchronously(const MethodReply& reply)
|
void Object::sendMethodReply(const MethodReply& reply)
|
||||||
{
|
{
|
||||||
connection_.sendReplyAsynchronously(reply);
|
connection_.sendMethodReply(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<sd_bus_vtable>& Object::createInterfaceVTable(InterfaceData& interfaceData)
|
const std::vector<sd_bus_vtable>& Object::createInterfaceVTable(InterfaceData& interfaceData)
|
||||||
|
@@ -84,7 +84,7 @@ namespace internal {
|
|||||||
sdbus::Signal createSignal(const std::string& interfaceName, const std::string& signalName) override;
|
sdbus::Signal createSignal(const std::string& interfaceName, const std::string& signalName) override;
|
||||||
void emitSignal(const sdbus::Signal& message) override;
|
void emitSignal(const sdbus::Signal& message) override;
|
||||||
|
|
||||||
void sendReplyAsynchronously(const MethodReply& reply);
|
void sendMethodReply(const MethodReply& reply);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using InterfaceName = std::string;
|
using InterfaceName = std::string;
|
||||||
|
@@ -49,7 +49,7 @@ ObjectProxy::ObjectProxy( std::unique_ptr<sdbus::internal::IConnection>&& connec
|
|||||||
{
|
{
|
||||||
// The connection is ours only, so we have to manage event loop upon this connection,
|
// The connection is ours only, so we have to manage event loop upon this connection,
|
||||||
// so we get signals, async replies, and other messages from D-Bus.
|
// so we get signals, async replies, and other messages from D-Bus.
|
||||||
connection_->enterProcessingLoopAsync();
|
// TODO uncomment connection_->enterProcessingLoopAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodCall ObjectProxy::createMethodCall(const std::string& interfaceName, const std::string& methodName)
|
MethodCall ObjectProxy::createMethodCall(const std::string& interfaceName, const std::string& methodName)
|
||||||
@@ -64,13 +64,16 @@ AsyncMethodCall ObjectProxy::createAsyncMethodCall(const std::string& interfaceN
|
|||||||
|
|
||||||
MethodReply ObjectProxy::callMethod(const MethodCall& message)
|
MethodReply ObjectProxy::callMethod(const MethodCall& message)
|
||||||
{
|
{
|
||||||
return message.send();
|
return connection_->callMethod(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectProxy::callMethod(const AsyncMethodCall& message, async_reply_handler asyncReplyCallback)
|
void ObjectProxy::callMethod(const AsyncMethodCall& message, async_reply_handler asyncReplyCallback)
|
||||||
{
|
{
|
||||||
// The new-ed handler gets deleted in the sdbus_async_reply_handler
|
auto callback = (void*)&ObjectProxy::sdbus_async_reply_handler;
|
||||||
message.send((void*)&ObjectProxy::sdbus_async_reply_handler, new async_reply_handler(std::move(asyncReplyCallback)));
|
// Allocated userData gets deleted in the sdbus_async_reply_handler
|
||||||
|
auto userData = new async_reply_handler(std::move(asyncReplyCallback));
|
||||||
|
|
||||||
|
connection_->callMethod(message, callback, userData);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectProxy::registerSignalHandler( const std::string& interfaceName
|
void ObjectProxy::registerSignalHandler( const std::string& interfaceName
|
||||||
|
@@ -3,25 +3,25 @@
|
|||||||
# https://github.com/google/googletest/blob/master/googletest/README.md#incorporating-into-an-existing-cmake-project
|
# https://github.com/google/googletest/blob/master/googletest/README.md#incorporating-into-an-existing-cmake-project
|
||||||
#-------------------------------
|
#-------------------------------
|
||||||
|
|
||||||
#configure_file(googletest-download/CMakeLists.txt.in googletest-download/CMakeLists.txt)
|
configure_file(googletest-download/CMakeLists.txt.in googletest-download/CMakeLists.txt)
|
||||||
|
|
||||||
#execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
|
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
|
||||||
# RESULT_VARIABLE result
|
RESULT_VARIABLE result
|
||||||
# WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download)
|
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download)
|
||||||
|
|
||||||
#if(result)
|
if(result)
|
||||||
# message(FATAL_ERROR "CMake step for googletest failed: ${result}")
|
message(FATAL_ERROR "CMake step for googletest failed: ${result}")
|
||||||
#endif()
|
endif()
|
||||||
|
|
||||||
#execute_process(COMMAND ${CMAKE_COMMAND} --build .
|
execute_process(COMMAND ${CMAKE_COMMAND} --build .
|
||||||
# RESULT_VARIABLE result
|
RESULT_VARIABLE result
|
||||||
# WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download)
|
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download)
|
||||||
|
|
||||||
#if(result)
|
if(result)
|
||||||
# message(FATAL_ERROR "Build step for googletest failed: ${result}")
|
message(FATAL_ERROR "Build step for googletest failed: ${result}")
|
||||||
#endif()
|
endif()
|
||||||
|
|
||||||
#set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||||
|
|
||||||
add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/googletest-src
|
add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/googletest-src
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/googletest-build
|
${CMAKE_CURRENT_BINARY_DIR}/googletest-build
|
||||||
@@ -63,8 +63,8 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
|||||||
# targets even when INTERFACE_INCLUDE_DIRECTORIES is used.
|
# targets even when INTERFACE_INCLUDE_DIRECTORIES is used.
|
||||||
set(CMAKE_NO_SYSTEM_FROM_IMPORTED "1")
|
set(CMAKE_NO_SYSTEM_FROM_IMPORTED "1")
|
||||||
|
|
||||||
add_executable(libsdbus-c++_unittests ${UNITTESTS_SRCS} $<TARGET_OBJECTS:sdbuscppobjects>)
|
#add_executable(libsdbus-c++_unittests ${UNITTESTS_SRCS} $<TARGET_OBJECTS:sdbuscppobjects>)
|
||||||
target_link_libraries(libsdbus-c++_unittests ${SYSTEMD_LIBRARIES} gmock gmock_main)
|
#target_link_libraries(libsdbus-c++_unittests ${SYSTEMD_LIBRARIES} gmock gmock_main)
|
||||||
|
|
||||||
add_executable(libsdbus-c++_integrationtests ${INTEGRATIONTESTS_SRCS})
|
add_executable(libsdbus-c++_integrationtests ${INTEGRATIONTESTS_SRCS})
|
||||||
target_link_libraries(libsdbus-c++_integrationtests sdbus-c++ gmock gmock_main)
|
target_link_libraries(libsdbus-c++_integrationtests sdbus-c++ gmock gmock_main)
|
||||||
@@ -82,7 +82,7 @@ endif()
|
|||||||
# INSTALLATION
|
# INSTALLATION
|
||||||
#----------------------------------
|
#----------------------------------
|
||||||
|
|
||||||
install(TARGETS libsdbus-c++_unittests DESTINATION /opt/test/bin)
|
#install(TARGETS libsdbus-c++_unittests DESTINATION /opt/test/bin)
|
||||||
install(TARGETS libsdbus-c++_integrationtests DESTINATION /opt/test/bin)
|
install(TARGETS libsdbus-c++_integrationtests DESTINATION /opt/test/bin)
|
||||||
install(FILES ${INTEGRATIONTESTS_SOURCE_DIR}/files/libsdbus-cpp-test.conf DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/dbus-1/system.d)
|
install(FILES ${INTEGRATIONTESTS_SOURCE_DIR}/files/libsdbus-cpp-test.conf DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/dbus-1/system.d)
|
||||||
|
|
||||||
@@ -107,9 +107,9 @@ if(CMAKE_CROSSCOMPILING)
|
|||||||
if(NOT (UNIT_TESTS_RUNNER AND TEST_DEVICE_IP))
|
if(NOT (UNIT_TESTS_RUNNER AND TEST_DEVICE_IP))
|
||||||
message(WARNING "UNIT_TESTS_RUNNER and TEST_DEVICE_IP variables must be defined to run tests remotely")
|
message(WARNING "UNIT_TESTS_RUNNER and TEST_DEVICE_IP variables must be defined to run tests remotely")
|
||||||
endif()
|
endif()
|
||||||
add_test(NAME libsdbus-c++_unittests COMMAND ${UNIT_TESTS_RUNNER} --deviceip=${TEST_DEVICE_IP} --testbin=libsdbus-c++_unittests)
|
#add_test(NAME libsdbus-c++_unittests COMMAND ${UNIT_TESTS_RUNNER} --deviceip=${TEST_DEVICE_IP} --testbin=libsdbus-c++_unittests)
|
||||||
add_test(NAME libsdbus-c++_integrationtests COMMAND ${UNIT_TESTS_RUNNER} --deviceip=${TEST_DEVICE_IP} --testbin=libsdbus-c++_integrationtests)
|
add_test(NAME libsdbus-c++_integrationtests COMMAND ${UNIT_TESTS_RUNNER} --deviceip=${TEST_DEVICE_IP} --testbin=libsdbus-c++_integrationtests)
|
||||||
else()
|
else()
|
||||||
add_test(NAME libsdbus-c++_unittests COMMAND libsdbus-c++_unittests)
|
#add_test(NAME libsdbus-c++_unittests COMMAND libsdbus-c++_unittests)
|
||||||
add_test(NAME libsdbus-c++_integrationtests COMMAND libsdbus-c++_integrationtests)
|
add_test(NAME libsdbus-c++_integrationtests COMMAND libsdbus-c++_integrationtests)
|
||||||
endif()
|
endif()
|
||||||
|
Reference in New Issue
Block a user