forked from Kistler-Group/sdbus-cpp
Re-design sdbus-c++ approach to connections (#47)
Fixes #33 , among others
This commit is contained in:
committed by
GitHub
parent
26c6ea8730
commit
fd7be39dd4
@ -28,7 +28,6 @@ set(SDBUSCPP_CPP_SRCS
|
||||
${SDBUSCPP_SOURCE_DIR}/ConvenienceClasses.cpp
|
||||
${SDBUSCPP_SOURCE_DIR}/Error.cpp
|
||||
${SDBUSCPP_SOURCE_DIR}/Message.cpp
|
||||
${SDBUSCPP_SOURCE_DIR}/MethodResult.cpp
|
||||
${SDBUSCPP_SOURCE_DIR}/Object.cpp
|
||||
${SDBUSCPP_SOURCE_DIR}/ObjectProxy.cpp
|
||||
${SDBUSCPP_SOURCE_DIR}/Types.cpp
|
||||
@ -58,10 +57,11 @@ set(SDBUSCPP_PUBLIC_HDRS
|
||||
${SDBUSCPP_INCLUDE_DIR}/IObjectProxy.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/Message.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/MethodResult.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/sdbus-c++.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/MethodResult.inl
|
||||
${SDBUSCPP_INCLUDE_DIR}/Types.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/TypeTraits.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/Flags.h)
|
||||
${SDBUSCPP_INCLUDE_DIR}/Flags.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/sdbus-c++.h)
|
||||
|
||||
set(SDBUSCPP_SRCS ${SDBUSCPP_CPP_SRCS} ${SDBUSCPP_HDR_SRCS} ${SDBUSCPP_PUBLIC_HDRS})
|
||||
|
||||
@ -94,6 +94,7 @@ set_target_properties(sdbus-c++
|
||||
VERSION "${SDBUSCPP_VERSION}"
|
||||
SOVERSION "${SDBUSCPP_VERSION_MAJOR}"
|
||||
OUTPUT_NAME "sdbus-c++")
|
||||
|
||||
target_link_libraries(sdbus-c++ ${SYSTEMD_LIBRARIES})
|
||||
|
||||
#----------------------------------
|
||||
|
@ -183,7 +183,6 @@ namespace sdbus {
|
||||
AsyncMethodInvoker(IObjectProxy& objectProxy, const std::string& methodName);
|
||||
AsyncMethodInvoker& onInterface(const std::string& interfaceName);
|
||||
template <typename... _Args> AsyncMethodInvoker& withArguments(_Args&&... args);
|
||||
//template <typename... _OutputArgs> void uponReplyInvoke(std::function<void(const Error*, _OutputArgs...)> callback);
|
||||
template <typename _Function> void uponReplyInvoke(_Function&& callback);
|
||||
|
||||
private:
|
||||
|
@ -113,7 +113,7 @@ namespace sdbus {
|
||||
{
|
||||
inputSignature_ = signature_of_function_input_arguments<_Function>::str();
|
||||
outputSignature_ = signature_of_function_output_arguments<_Function>::str();
|
||||
asyncCallback_ = [callback = std::forward<_Function>(callback)](MethodCall& msg, MethodResult result)
|
||||
asyncCallback_ = [callback = std::forward<_Function>(callback)](MethodCall msg, MethodResult&& result)
|
||||
{
|
||||
// Create a tuple of callback input arguments' types, which will be used
|
||||
// as a storage for the argument values deserialized from the message.
|
||||
@ -123,7 +123,7 @@ namespace sdbus {
|
||||
msg >> inputArgs;
|
||||
|
||||
// Invoke callback with input arguments from the tuple.
|
||||
sdbus::apply(callback, std::move(result), inputArgs); // TODO: Use std::apply when switching to full C++17 support
|
||||
sdbus::apply(callback, std::move(result), std::move(inputArgs)); // TODO: Use std::apply when switching to full C++17 support
|
||||
};
|
||||
|
||||
return *this;
|
||||
|
@ -70,12 +70,12 @@ namespace sdbus {
|
||||
sdbus::Error createError(int errNo, const std::string& customMsg);
|
||||
}
|
||||
|
||||
#define SDBUS_THROW_ERROR(_MSG, _ERRNO) \
|
||||
throw sdbus::createError((_ERRNO), (_MSG)) \
|
||||
#define SDBUS_THROW_ERROR(_MSG, _ERRNO) \
|
||||
throw sdbus::createError((_ERRNO), (_MSG)) \
|
||||
/**/
|
||||
|
||||
#define SDBUS_THROW_ERROR_IF(_COND, _MSG, _ERRNO) \
|
||||
if (_COND) SDBUS_THROW_ERROR((_MSG), (_ERRNO)) \
|
||||
#define SDBUS_THROW_ERROR_IF(_COND, _MSG, _ERRNO) \
|
||||
if (!(_COND)) ; else SDBUS_THROW_ERROR((_MSG), (_ERRNO)) \
|
||||
/**/
|
||||
|
||||
#endif /* SDBUS_CXX_ERROR_H_ */
|
||||
|
@ -50,10 +50,22 @@ namespace sdbus {
|
||||
class MethodReply;
|
||||
class Signal;
|
||||
template <typename... _Results> class Result;
|
||||
|
||||
namespace internal {
|
||||
class ISdBus;
|
||||
}
|
||||
}
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
// Assume the caller has already obtained message ownership
|
||||
struct adopt_message_t { explicit adopt_message_t() = default; };
|
||||
#ifdef __cpp_inline_variables
|
||||
inline constexpr adopt_message_t adopt_message{};
|
||||
#else
|
||||
constexpr adopt_message_t adopt_message{};
|
||||
#endif
|
||||
|
||||
/********************************************//**
|
||||
* @class Message
|
||||
*
|
||||
@ -72,7 +84,9 @@ namespace sdbus {
|
||||
{
|
||||
public:
|
||||
Message() = default;
|
||||
Message(void *msg) noexcept;
|
||||
Message(internal::ISdBus* sdbus) noexcept;
|
||||
Message(void *msg, internal::ISdBus* sdbus) noexcept;
|
||||
Message(void *msg, internal::ISdBus* sdbus, adopt_message_t) noexcept;
|
||||
Message(const Message&) noexcept;
|
||||
Message& operator=(const Message&) noexcept;
|
||||
Message(Message&& other) noexcept;
|
||||
@ -141,10 +155,8 @@ namespace sdbus {
|
||||
void rewind(bool complete);
|
||||
|
||||
protected:
|
||||
void* getMsg() const;
|
||||
|
||||
private:
|
||||
void* msg_{};
|
||||
internal::ISdBus* sdbus_{};
|
||||
mutable bool ok_{true};
|
||||
};
|
||||
|
||||
@ -167,6 +179,7 @@ namespace sdbus {
|
||||
{
|
||||
public:
|
||||
using Message::Message;
|
||||
AsyncMethodCall() = default; // Fixes gcc 6.3 error (default c-tor is not imported in above using declaration)
|
||||
AsyncMethodCall(MethodCall&& call) noexcept;
|
||||
void send(void* callback, void* userData) const;
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
*
|
||||
* @file ConvenienceClasses.h
|
||||
* @file MethodResult.h
|
||||
*
|
||||
* Created on: Nov 8, 2016
|
||||
* Project: sdbus-c++
|
||||
@ -51,40 +51,23 @@ namespace sdbus {
|
||||
{
|
||||
protected:
|
||||
friend sdbus::internal::Object;
|
||||
|
||||
MethodResult() = default;
|
||||
MethodResult(const MethodCall& msg, sdbus::internal::Object& object);
|
||||
MethodResult(MethodCall msg);
|
||||
|
||||
MethodResult(const MethodResult&) = delete;
|
||||
MethodResult& operator=(const MethodResult&) = delete;
|
||||
|
||||
MethodResult(MethodResult&& other) = default;
|
||||
MethodResult& operator=(MethodResult&& other) = default;
|
||||
|
||||
template <typename... _Results> void returnResults(const _Results&... results) const;
|
||||
void returnError(const Error& error) const;
|
||||
|
||||
private:
|
||||
void send(const MethodReply& reply) const;
|
||||
|
||||
private:
|
||||
MethodCall call_;
|
||||
sdbus::internal::Object* object_{};
|
||||
};
|
||||
|
||||
template <typename... _Results>
|
||||
inline void MethodResult::returnResults(const _Results&... results) const
|
||||
{
|
||||
assert(call_.isValid());
|
||||
auto reply = call_.createReply();
|
||||
#ifdef __cpp_fold_expressions
|
||||
(reply << ... << results);
|
||||
#else
|
||||
using _ = std::initializer_list<int>;
|
||||
(void)_{(void(reply << results), 0)...};
|
||||
#endif
|
||||
send(reply);
|
||||
}
|
||||
|
||||
inline void MethodResult::returnError(const Error& error) const
|
||||
{
|
||||
auto reply = call_.createErrorReply(error);
|
||||
send(reply);
|
||||
}
|
||||
|
||||
/********************************************//**
|
||||
* @class Result
|
||||
*
|
||||
@ -98,29 +81,14 @@ namespace sdbus {
|
||||
{
|
||||
public:
|
||||
Result() = default;
|
||||
Result(MethodResult result);
|
||||
Result(MethodResult&& result);
|
||||
|
||||
void returnResults(const _Results&... results) const;
|
||||
void returnError(const Error& error) const;
|
||||
};
|
||||
|
||||
template <typename... _Results>
|
||||
inline Result<_Results...>::Result(MethodResult result)
|
||||
: MethodResult(std::move(result))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename... _Results>
|
||||
inline void Result<_Results...>::returnResults(const _Results&... results) const
|
||||
{
|
||||
MethodResult::returnResults(results...);
|
||||
}
|
||||
|
||||
template <typename... _Results>
|
||||
inline void Result<_Results...>::returnError(const Error& error) const
|
||||
{
|
||||
MethodResult::returnError(error);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include <sdbus-c++/MethodResult.inl>
|
||||
|
||||
#endif /* SDBUS_CXX_METHODRESULT_H_ */
|
||||
|
79
include/sdbus-c++/MethodResult.inl
Executable file
79
include/sdbus-c++/MethodResult.inl
Executable file
@ -0,0 +1,79 @@
|
||||
/**
|
||||
* (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
*
|
||||
* @file MethodResult.inl
|
||||
*
|
||||
* Created on: Mar 21, 2019
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SDBUS_CXX_METHODRESULT_INL_
|
||||
#define SDBUS_CXX_METHODRESULT_INL_
|
||||
|
||||
#include <sdbus-c++/MethodResult.h>
|
||||
#include <cassert>
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
inline MethodResult::MethodResult(MethodCall msg)
|
||||
: call_(std::move(msg))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename... _Results>
|
||||
inline void MethodResult::returnResults(const _Results&... results) const
|
||||
{
|
||||
assert(call_.isValid());
|
||||
auto reply = call_.createReply();
|
||||
#ifdef __cpp_fold_expressions
|
||||
(reply << ... << results);
|
||||
#else
|
||||
using _ = std::initializer_list<int>;
|
||||
(void)_{(void(reply << results), 0)...};
|
||||
#endif
|
||||
reply.send();
|
||||
}
|
||||
|
||||
inline void MethodResult::returnError(const Error& error) const
|
||||
{
|
||||
auto reply = call_.createErrorReply(error);
|
||||
reply.send();
|
||||
}
|
||||
|
||||
template <typename... _Results>
|
||||
inline Result<_Results...>::Result(MethodResult&& result)
|
||||
: MethodResult(std::move(result))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename... _Results>
|
||||
inline void Result<_Results...>::returnResults(const _Results&... results) const
|
||||
{
|
||||
MethodResult::returnResults(results...);
|
||||
}
|
||||
|
||||
template <typename... _Results>
|
||||
inline void Result<_Results...>::returnError(const Error& error) const
|
||||
{
|
||||
MethodResult::returnError(error);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif /* SDBUS_CXX_METHODRESULT_INL_ */
|
@ -52,7 +52,7 @@ namespace sdbus {
|
||||
namespace sdbus {
|
||||
|
||||
using method_callback = std::function<void(MethodCall& msg, MethodReply& reply)>;
|
||||
using async_method_callback = std::function<void(MethodCall& msg, MethodResult result)>;
|
||||
using async_method_callback = std::function<void(MethodCall msg, MethodResult&& result)>;
|
||||
using async_reply_handler = std::function<void(MethodReply& reply, const Error* error)>;
|
||||
using signal_handler = std::function<void(Signal& signal)>;
|
||||
using property_set_callback = std::function<void(Message& msg)>;
|
||||
@ -383,6 +383,13 @@ namespace sdbus {
|
||||
static constexpr bool is_async = true;
|
||||
};
|
||||
|
||||
template <typename... _Args, typename... _Results>
|
||||
struct function_traits<void(Result<_Results...>&&, _Args...)>
|
||||
: public function_traits_base<std::tuple<_Results...>, _Args...>
|
||||
{
|
||||
static constexpr bool is_async = true;
|
||||
};
|
||||
|
||||
template <typename _ReturnType, typename... _Args>
|
||||
struct function_traits<_ReturnType(*)(_Args...)>
|
||||
: public function_traits<_ReturnType(_Args...)>
|
||||
|
@ -139,20 +139,22 @@ namespace sdbus {
|
||||
{
|
||||
public:
|
||||
using std::string::string;
|
||||
using std::string::operator=;
|
||||
ObjectPath() = default; // Fixes gcc 6.3 error (default c-tor is not imported in above using declaration)
|
||||
ObjectPath(std::string path)
|
||||
: std::string(std::move(path))
|
||||
{}
|
||||
using std::string::operator=;
|
||||
};
|
||||
|
||||
class Signature : public std::string
|
||||
{
|
||||
public:
|
||||
using std::string::string;
|
||||
using std::string::operator=;
|
||||
Signature() = default; // Fixes gcc 6.3 error (default c-tor is not imported in above using declaration)
|
||||
Signature(std::string path)
|
||||
: std::string(std::move(path))
|
||||
{}
|
||||
using std::string::operator=;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -36,21 +36,23 @@
|
||||
namespace sdbus { namespace internal {
|
||||
|
||||
Connection::Connection(Connection::BusType type, std::unique_ptr<ISdBus>&& interface)
|
||||
: busType_(type)
|
||||
, iface_(std::move(interface))
|
||||
: iface_(std::move(interface))
|
||||
, busType_(type)
|
||||
{
|
||||
assert(iface_ != nullptr);
|
||||
|
||||
auto bus = openBus(busType_);
|
||||
bus_.reset(bus);
|
||||
|
||||
finishHandshake(bus);
|
||||
|
||||
notificationFd_ = createLoopNotificationDescriptor();
|
||||
loopExitFd_ = createProcessingLoopExitDescriptor();
|
||||
}
|
||||
|
||||
Connection::~Connection()
|
||||
{
|
||||
leaveProcessingLoop();
|
||||
closeLoopNotificationDescriptor(notificationFd_);
|
||||
closeProcessingLoopExitDescriptor(loopExitFd_);
|
||||
}
|
||||
|
||||
void Connection::requestName(const std::string& name)
|
||||
@ -76,14 +78,13 @@ void Connection::enterProcessingLoop()
|
||||
auto success = waitForNextRequest();
|
||||
if (!success)
|
||||
break; // Exit processing loop
|
||||
if (success.asyncMsgsToProcess)
|
||||
processAsynchronousMessages();
|
||||
}
|
||||
}
|
||||
|
||||
void Connection::enterProcessingLoopAsync()
|
||||
{
|
||||
asyncLoopThread_ = std::thread([this](){ enterProcessingLoop(); });
|
||||
if (!asyncLoopThread_.joinable())
|
||||
asyncLoopThread_ = std::thread([this](){ enterProcessingLoop(); });
|
||||
}
|
||||
|
||||
void Connection::leaveProcessingLoop()
|
||||
@ -92,6 +93,16 @@ void Connection::leaveProcessingLoop()
|
||||
joinWithProcessingLoop();
|
||||
}
|
||||
|
||||
const ISdBus& Connection::getSdBusInterface() const
|
||||
{
|
||||
return *iface_.get();
|
||||
}
|
||||
|
||||
ISdBus& Connection::getSdBusInterface()
|
||||
{
|
||||
return *iface_.get();
|
||||
}
|
||||
|
||||
sd_bus_slot* Connection::addObjectVTable( const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const sd_bus_vtable* vtable
|
||||
@ -116,16 +127,13 @@ void Connection::removeObjectVTable(sd_bus_slot* vtableHandle)
|
||||
iface_->sd_bus_slot_unref(vtableHandle);
|
||||
}
|
||||
|
||||
sdbus::MethodCall Connection::createMethodCall( const std::string& destination
|
||||
, const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const std::string& methodName ) const
|
||||
MethodCall Connection::createMethodCall( const std::string& destination
|
||||
, const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const std::string& methodName ) const
|
||||
{
|
||||
sd_bus_message *sdbusMsg{};
|
||||
|
||||
// Returned message will become an owner of sdbusMsg
|
||||
SCOPE_EXIT{ iface_->sd_bus_message_unref(sdbusMsg); };
|
||||
|
||||
auto r = iface_->sd_bus_message_new_method_call( bus_.get()
|
||||
, &sdbusMsg
|
||||
, destination.c_str()
|
||||
@ -135,18 +143,15 @@ sdbus::MethodCall Connection::createMethodCall( const std::string& destination
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to create method call", -r);
|
||||
|
||||
return MethodCall(sdbusMsg);
|
||||
return MethodCall{sdbusMsg, iface_.get(), adopt_message};
|
||||
}
|
||||
|
||||
sdbus::Signal Connection::createSignal( const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const std::string& signalName ) const
|
||||
Signal Connection::createSignal( const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const std::string& signalName ) const
|
||||
{
|
||||
sd_bus_message *sdbusSignal{};
|
||||
|
||||
// Returned message will become an owner of sdbusSignal
|
||||
SCOPE_EXIT{ iface_->sd_bus_message_unref(sdbusSignal); };
|
||||
|
||||
auto r = iface_->sd_bus_message_new_signal( bus_.get()
|
||||
, &sdbusSignal
|
||||
, objectPath.c_str()
|
||||
@ -155,7 +160,7 @@ sdbus::Signal Connection::createSignal( const std::string& objectPath
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to create signal", -r);
|
||||
|
||||
return Signal(sdbusSignal);
|
||||
return Signal{sdbusSignal, iface_.get(), adopt_message};
|
||||
}
|
||||
|
||||
sd_bus_slot* Connection::registerSignalHandler( const std::string& objectPath
|
||||
@ -179,20 +184,6 @@ void Connection::unregisterSignalHandler(sd_bus_slot* handlerCookie)
|
||||
iface_->sd_bus_slot_unref(handlerCookie);
|
||||
}
|
||||
|
||||
void Connection::sendReplyAsynchronously(const sdbus::MethodReply& reply)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
asyncReplies_.push(reply);
|
||||
notifyProcessingLoop();
|
||||
}
|
||||
|
||||
std::unique_ptr<sdbus::internal::IConnection> Connection::clone() const
|
||||
{
|
||||
auto interface = std::make_unique<SdBus>();
|
||||
assert(interface != nullptr);
|
||||
return std::make_unique<sdbus::internal::Connection>(busType_, std::move(interface));
|
||||
}
|
||||
|
||||
sd_bus* Connection::openBus(Connection::BusType type)
|
||||
{
|
||||
sd_bus* bus{};
|
||||
@ -223,7 +214,7 @@ void Connection::finishHandshake(sd_bus* bus)
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to flush bus on opening", -r);
|
||||
}
|
||||
|
||||
int Connection::createLoopNotificationDescriptor()
|
||||
int Connection::createProcessingLoopExitDescriptor()
|
||||
{
|
||||
auto r = eventfd(0, EFD_SEMAPHORE | EFD_CLOEXEC | EFD_NONBLOCK);
|
||||
|
||||
@ -232,26 +223,25 @@ int Connection::createLoopNotificationDescriptor()
|
||||
return r;
|
||||
}
|
||||
|
||||
void Connection::closeLoopNotificationDescriptor(int fd)
|
||||
void Connection::closeProcessingLoopExitDescriptor(int fd)
|
||||
{
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void Connection::notifyProcessingLoop()
|
||||
void Connection::notifyProcessingLoopToExit()
|
||||
{
|
||||
assert(notificationFd_ >= 0);
|
||||
assert(loopExitFd_ >= 0);
|
||||
|
||||
uint64_t value = 1;
|
||||
auto r = write(notificationFd_, &value, sizeof(value));
|
||||
|
||||
auto r = write(loopExitFd_, &value, sizeof(value));
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to notify processing loop", -errno);
|
||||
}
|
||||
|
||||
void Connection::notifyProcessingLoopToExit()
|
||||
void Connection::clearExitNotification()
|
||||
{
|
||||
exitLoopThread_ = true;
|
||||
|
||||
notifyProcessingLoop();
|
||||
uint64_t value{};
|
||||
auto r = read(loopExitFd_, &value, sizeof(value));
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to read from the event descriptor", -errno);
|
||||
}
|
||||
|
||||
void Connection::joinWithProcessingLoop()
|
||||
@ -273,60 +263,35 @@ bool Connection::processPendingRequest()
|
||||
return r > 0;
|
||||
}
|
||||
|
||||
void Connection::processAsynchronousMessages()
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
while (!asyncReplies_.empty())
|
||||
{
|
||||
auto reply = asyncReplies_.front();
|
||||
asyncReplies_.pop();
|
||||
reply.send();
|
||||
}
|
||||
}
|
||||
|
||||
Connection::WaitResult Connection::waitForNextRequest()
|
||||
bool Connection::waitForNextRequest()
|
||||
{
|
||||
auto bus = bus_.get();
|
||||
|
||||
assert(bus != nullptr);
|
||||
assert(notificationFd_ != 0);
|
||||
assert(loopExitFd_ != 0);
|
||||
|
||||
auto r = iface_->sd_bus_get_fd(bus);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus descriptor", -r);
|
||||
auto sdbusFd = r;
|
||||
ISdBus::PollData sdbusPollData;
|
||||
auto r = iface_->sd_bus_get_poll_data(bus, &sdbusPollData);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus poll data", -r);
|
||||
|
||||
r = iface_->sd_bus_get_events(bus);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus events", -r);
|
||||
short int sdbusEvents = r;
|
||||
|
||||
uint64_t usec;
|
||||
iface_->sd_bus_get_timeout(bus, &usec);
|
||||
|
||||
struct pollfd fds[] = {{sdbusFd, sdbusEvents, 0}, {notificationFd_, POLLIN, 0}};
|
||||
struct pollfd fds[] = {{sdbusPollData.fd, sdbusPollData.events, 0}, {loopExitFd_, POLLIN, 0}};
|
||||
auto fdsCount = sizeof(fds)/sizeof(fds[0]);
|
||||
|
||||
r = poll(fds, fdsCount, usec == (uint64_t) -1 ? -1 : (usec+999)/1000);
|
||||
auto timeout = sdbusPollData.timeout_usec == (uint64_t) -1 ? (uint64_t)-1 : (sdbusPollData.timeout_usec+999)/1000;
|
||||
r = poll(fds, fdsCount, timeout);
|
||||
|
||||
if (r < 0 && errno == EINTR)
|
||||
return {true, false}; // Try again
|
||||
return true; // Try again
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to wait on the bus", -errno);
|
||||
|
||||
if (fds[1].revents & POLLIN)
|
||||
{
|
||||
if (exitLoopThread_)
|
||||
return {false, false}; // Got exit notification
|
||||
|
||||
// Otherwise we have some async messages to process
|
||||
|
||||
uint64_t value{};
|
||||
auto r = read(notificationFd_, &value, sizeof(value));
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to read from the event descriptor", -errno);
|
||||
|
||||
return {false, true};
|
||||
clearExitNotification();
|
||||
return false;
|
||||
}
|
||||
|
||||
return {true, false};
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string Connection::composeSignalMatchFilter( const std::string& objectPath
|
||||
@ -361,8 +326,8 @@ std::unique_ptr<sdbus::IConnection> createSystemBusConnection()
|
||||
{
|
||||
auto interface = std::make_unique<sdbus::internal::SdBus>();
|
||||
assert(interface != nullptr);
|
||||
return std::make_unique<sdbus::internal::Connection>(sdbus::internal::Connection::BusType::eSystem,
|
||||
std::move(interface));
|
||||
return std::make_unique<sdbus::internal::Connection>( sdbus::internal::Connection::BusType::eSystem
|
||||
, std::move(interface));
|
||||
}
|
||||
|
||||
std::unique_ptr<sdbus::IConnection> createSystemBusConnection(const std::string& name)
|
||||
@ -376,8 +341,8 @@ std::unique_ptr<sdbus::IConnection> createSessionBusConnection()
|
||||
{
|
||||
auto interface = std::make_unique<sdbus::internal::SdBus>();
|
||||
assert(interface != nullptr);
|
||||
return std::make_unique<sdbus::internal::Connection>(sdbus::internal::Connection::BusType::eSession,
|
||||
std::move(interface));
|
||||
return std::make_unique<sdbus::internal::Connection>( sdbus::internal::Connection::BusType::eSession
|
||||
, std::move(interface));
|
||||
}
|
||||
|
||||
std::unique_ptr<sdbus::IConnection> createSessionBusConnection(const std::string& name)
|
||||
|
@ -29,14 +29,11 @@
|
||||
#include <sdbus-c++/IConnection.h>
|
||||
#include <sdbus-c++/Message.h>
|
||||
#include "IConnection.h"
|
||||
#include "ScopeGuard.h"
|
||||
#include "ISdBus.h"
|
||||
|
||||
#include <systemd/sd-bus.h>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
|
||||
namespace sdbus { namespace internal {
|
||||
|
||||
@ -60,19 +57,22 @@ namespace sdbus { namespace internal {
|
||||
void enterProcessingLoopAsync() override;
|
||||
void leaveProcessingLoop() override;
|
||||
|
||||
const ISdBus& getSdBusInterface() const override;
|
||||
ISdBus& getSdBusInterface() override;
|
||||
|
||||
sd_bus_slot* addObjectVTable( const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const sd_bus_vtable* vtable
|
||||
, void* userData ) override;
|
||||
void removeObjectVTable(sd_bus_slot* vtableHandle) override;
|
||||
|
||||
sdbus::MethodCall createMethodCall( const std::string& destination
|
||||
, const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const std::string& methodName ) const override;
|
||||
sdbus::Signal createSignal( const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const std::string& signalName ) 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;
|
||||
|
||||
sd_bus_slot* registerSignalHandler( const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
@ -81,32 +81,18 @@ namespace sdbus { namespace internal {
|
||||
, void* userData ) override;
|
||||
void unregisterSignalHandler(sd_bus_slot* handlerCookie) override;
|
||||
|
||||
void sendReplyAsynchronously(const sdbus::MethodReply& reply) override;
|
||||
|
||||
std::unique_ptr<sdbus::internal::IConnection> clone() const override;
|
||||
|
||||
private:
|
||||
struct WaitResult
|
||||
{
|
||||
bool msgsToProcess;
|
||||
bool asyncMsgsToProcess;
|
||||
operator bool()
|
||||
{
|
||||
return msgsToProcess || asyncMsgsToProcess;
|
||||
}
|
||||
};
|
||||
sd_bus* openBus(Connection::BusType type);
|
||||
void finishHandshake(sd_bus* bus);
|
||||
static int createLoopNotificationDescriptor();
|
||||
static void closeLoopNotificationDescriptor(int fd);
|
||||
static int createProcessingLoopExitDescriptor();
|
||||
static void closeProcessingLoopExitDescriptor(int fd);
|
||||
bool processPendingRequest();
|
||||
void processAsynchronousMessages();
|
||||
WaitResult waitForNextRequest();
|
||||
bool waitForNextRequest();
|
||||
static std::string composeSignalMatchFilter( const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const std::string& signalName );
|
||||
void notifyProcessingLoop();
|
||||
void notifyProcessingLoopToExit();
|
||||
void clearExitNotification();
|
||||
void joinWithProcessingLoop();
|
||||
|
||||
private:
|
||||
@ -115,14 +101,10 @@ namespace sdbus { namespace internal {
|
||||
{
|
||||
return iface_->sd_bus_flush_close_unref(bus);
|
||||
}};
|
||||
std::thread asyncLoopThread_;
|
||||
std::mutex mutex_;
|
||||
std::queue<MethodReply> asyncReplies_;
|
||||
std::atomic<bool> exitLoopThread_;
|
||||
int notificationFd_{-1};
|
||||
BusType busType_;
|
||||
|
||||
static constexpr const uint64_t POLL_TIMEOUT_USEC = 500000;
|
||||
std::thread asyncLoopThread_;
|
||||
int loopExitFd_{-1};
|
||||
};
|
||||
|
||||
}}
|
||||
|
@ -33,8 +33,12 @@
|
||||
// Forward declaration
|
||||
namespace sdbus {
|
||||
class MethodCall;
|
||||
class AsyncMethodCall;
|
||||
class MethodReply;
|
||||
class Signal;
|
||||
namespace internal {
|
||||
class ISdBus;
|
||||
}
|
||||
}
|
||||
|
||||
namespace sdbus {
|
||||
@ -43,20 +47,23 @@ namespace internal {
|
||||
class IConnection
|
||||
{
|
||||
public:
|
||||
virtual const ISdBus& getSdBusInterface() const = 0;
|
||||
virtual ISdBus& getSdBusInterface() = 0;
|
||||
|
||||
virtual sd_bus_slot* addObjectVTable( const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const sd_bus_vtable* vtable
|
||||
, void* userData ) = 0;
|
||||
virtual void removeObjectVTable(sd_bus_slot* vtableHandle) = 0;
|
||||
|
||||
virtual sdbus::MethodCall createMethodCall( const std::string& destination
|
||||
, const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const std::string& methodName ) const = 0;
|
||||
virtual MethodCall createMethodCall( const std::string& destination
|
||||
, const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const std::string& methodName ) const = 0;
|
||||
|
||||
virtual sdbus::Signal createSignal( const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const std::string& signalName ) const = 0;
|
||||
virtual Signal createSignal( const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const std::string& signalName ) const = 0;
|
||||
|
||||
virtual sd_bus_slot* registerSignalHandler( const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
@ -68,10 +75,6 @@ namespace internal {
|
||||
virtual void enterProcessingLoopAsync() = 0;
|
||||
virtual void leaveProcessingLoop() = 0;
|
||||
|
||||
virtual void sendReplyAsynchronously(const sdbus::MethodReply& reply) = 0;
|
||||
|
||||
virtual std::unique_ptr<sdbus::internal::IConnection> clone() const = 0;
|
||||
|
||||
virtual ~IConnection() = default;
|
||||
};
|
||||
|
||||
|
36
src/ISdBus.h
36
src/ISdBus.h
@ -34,21 +34,37 @@ namespace sdbus { namespace internal {
|
||||
class ISdBus
|
||||
{
|
||||
public:
|
||||
struct PollData
|
||||
{
|
||||
int fd;
|
||||
short int events;
|
||||
uint64_t timeout_usec;
|
||||
};
|
||||
|
||||
virtual sd_bus_message* sd_bus_message_ref(sd_bus_message *m) = 0;
|
||||
virtual sd_bus_message* sd_bus_message_unref(sd_bus_message *m) = 0;
|
||||
|
||||
virtual int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *cookie) = 0;
|
||||
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_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;
|
||||
virtual int sd_bus_message_new_method_error(sd_bus_message *call, sd_bus_message **m, const sd_bus_error *e) = 0;
|
||||
|
||||
virtual int sd_bus_open_user(sd_bus **ret) = 0;
|
||||
virtual int sd_bus_open_system(sd_bus **ret) = 0;
|
||||
virtual int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags) = 0;
|
||||
virtual int sd_bus_release_name(sd_bus *bus, const char *name) = 0;
|
||||
virtual int sd_bus_add_object_vtable(sd_bus *bus, sd_bus_slot **slot, const char *path, const char *interface, const sd_bus_vtable *vtable, void *userdata) = 0;
|
||||
virtual sd_bus_slot* sd_bus_slot_unref(sd_bus_slot *slot) = 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 sd_bus_message* sd_bus_message_unref(sd_bus_message *m) = 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_add_match(sd_bus *bus, sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, void *userdata) = 0;
|
||||
virtual int sd_bus_open_user(sd_bus **ret) = 0;
|
||||
virtual int sd_bus_open_system(sd_bus **ret) = 0;
|
||||
virtual int sd_bus_flush(sd_bus *bus) = 0;
|
||||
virtual sd_bus_slot* sd_bus_slot_unref(sd_bus_slot *slot) = 0;
|
||||
|
||||
virtual int sd_bus_process(sd_bus *bus, sd_bus_message **r) = 0;
|
||||
virtual int sd_bus_get_fd(sd_bus *bus) = 0;
|
||||
virtual int sd_bus_get_events(sd_bus *bus) = 0;
|
||||
virtual int sd_bus_get_timeout(sd_bus *bus, uint64_t *timeout_usec) = 0;
|
||||
virtual int sd_bus_get_poll_data(sd_bus *bus, PollData* data) = 0;
|
||||
|
||||
virtual int sd_bus_flush(sd_bus *bus) = 0;
|
||||
virtual sd_bus *sd_bus_flush_close_unref(sd_bus *bus) = 0;
|
||||
|
||||
virtual ~ISdBus() = default;
|
||||
|
@ -27,17 +27,34 @@
|
||||
#include <sdbus-c++/Types.h>
|
||||
#include <sdbus-c++/Error.h>
|
||||
#include "MessageUtils.h"
|
||||
#include "SdBus.h"
|
||||
#include "ScopeGuard.h"
|
||||
#include <systemd/sd-bus.h>
|
||||
#include <cassert>
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
Message::Message(void *msg) noexcept
|
||||
Message::Message(internal::ISdBus* sdbus) noexcept
|
||||
: sdbus_(sdbus)
|
||||
{
|
||||
assert(sdbus_ != nullptr);
|
||||
}
|
||||
|
||||
Message::Message(void *msg, internal::ISdBus* sdbus) noexcept
|
||||
: msg_(msg)
|
||||
, sdbus_(sdbus)
|
||||
{
|
||||
assert(msg_ != nullptr);
|
||||
sd_bus_message_ref((sd_bus_message*)msg_);
|
||||
assert(sdbus_ != nullptr);
|
||||
sdbus_->sd_bus_message_ref((sd_bus_message*)msg_);
|
||||
}
|
||||
|
||||
Message::Message(void *msg, internal::ISdBus* sdbus, adopt_message_t) noexcept
|
||||
: msg_(msg)
|
||||
, sdbus_(sdbus)
|
||||
{
|
||||
assert(msg_ != nullptr);
|
||||
assert(sdbus_ != nullptr);
|
||||
}
|
||||
|
||||
Message::Message(const Message& other) noexcept
|
||||
@ -48,12 +65,13 @@ Message::Message(const Message& other) noexcept
|
||||
Message& Message::operator=(const Message& other) noexcept
|
||||
{
|
||||
if (msg_)
|
||||
sd_bus_message_unref((sd_bus_message*)msg_);
|
||||
sdbus_->sd_bus_message_unref((sd_bus_message*)msg_);
|
||||
|
||||
msg_ = other.msg_;
|
||||
sdbus_ = other.sdbus_;
|
||||
ok_ = other.ok_;
|
||||
|
||||
sd_bus_message_ref((sd_bus_message*)msg_);
|
||||
sdbus_->sd_bus_message_ref((sd_bus_message*)msg_);
|
||||
|
||||
return *this;
|
||||
}
|
||||
@ -66,10 +84,12 @@ Message::Message(Message&& other) noexcept
|
||||
Message& Message::operator=(Message&& other) noexcept
|
||||
{
|
||||
if (msg_)
|
||||
sd_bus_message_unref((sd_bus_message*)msg_);
|
||||
sdbus_->sd_bus_message_unref((sd_bus_message*)msg_);
|
||||
|
||||
msg_ = other.msg_;
|
||||
other.msg_ = nullptr;
|
||||
sdbus_ = other.sdbus_;
|
||||
other.sdbus_ = nullptr;
|
||||
ok_ = other.ok_;
|
||||
other.ok_ = true;
|
||||
|
||||
@ -79,7 +99,7 @@ Message& Message::operator=(Message&& other) noexcept
|
||||
Message::~Message()
|
||||
{
|
||||
if (msg_)
|
||||
sd_bus_message_unref((sd_bus_message*)msg_);
|
||||
sdbus_->sd_bus_message_unref((sd_bus_message*)msg_);
|
||||
}
|
||||
|
||||
Message& Message::operator<<(bool item)
|
||||
@ -558,7 +578,7 @@ void Message::peekType(std::string& type, std::string& contents) const
|
||||
|
||||
bool Message::isValid() const
|
||||
{
|
||||
return msg_ != nullptr;
|
||||
return msg_ != nullptr && sdbus_ != nullptr;
|
||||
}
|
||||
|
||||
bool Message::isEmpty() const
|
||||
@ -566,20 +586,15 @@ bool Message::isEmpty() const
|
||||
return sd_bus_message_is_empty((sd_bus_message*)msg_);
|
||||
}
|
||||
|
||||
void* Message::getMsg() const
|
||||
{
|
||||
return msg_;
|
||||
}
|
||||
|
||||
void MethodCall::dontExpectReply()
|
||||
{
|
||||
auto r = sd_bus_message_set_expect_reply((sd_bus_message*)getMsg(), 0);
|
||||
auto r = sd_bus_message_set_expect_reply((sd_bus_message*)msg_, 0);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set the dont-expect-reply flag", -r);
|
||||
}
|
||||
|
||||
bool MethodCall::doesntExpectReply() const
|
||||
{
|
||||
auto r = sd_bus_message_get_expect_reply((sd_bus_message*)getMsg());
|
||||
auto r = sd_bus_message_get_expect_reply((sd_bus_message*)msg_);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get the dont-expect-reply flag", -r);
|
||||
return r > 0 ? false : true;
|
||||
}
|
||||
@ -594,41 +609,35 @@ MethodReply MethodCall::send() const
|
||||
|
||||
MethodReply MethodCall::sendWithReply() const
|
||||
{
|
||||
sd_bus_message* sdbusReply{};
|
||||
SCOPE_EXIT{ sd_bus_message_unref(sdbusReply); }; // Returned message will become an owner of sdbusReply
|
||||
sd_bus_error sdbusError = SD_BUS_ERROR_NULL;
|
||||
SCOPE_EXIT{ sd_bus_error_free(&sdbusError); };
|
||||
|
||||
auto r = sd_bus_call(nullptr, (sd_bus_message*)getMsg(), 0, &sdbusError, &sdbusReply);
|
||||
sd_bus_message* sdbusReply{};
|
||||
auto r = sdbus_->sd_bus_call(nullptr, (sd_bus_message*)msg_, 0, &sdbusError, &sdbusReply);
|
||||
|
||||
if (sd_bus_error_is_set(&sdbusError))
|
||||
{
|
||||
throw sdbus::Error(sdbusError.name, sdbusError.message);
|
||||
}
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to call method", -r);
|
||||
|
||||
return MethodReply(sdbusReply);
|
||||
return MethodReply{sdbusReply, sdbus_, adopt_message};
|
||||
}
|
||||
|
||||
MethodReply MethodCall::sendWithNoReply() const
|
||||
{
|
||||
auto r = sd_bus_send(nullptr, (sd_bus_message*)getMsg(), nullptr);
|
||||
auto r = sdbus_->sd_bus_send(nullptr, (sd_bus_message*)msg_, nullptr);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to call method with no reply", -r);
|
||||
|
||||
return MethodReply{}; // No reply
|
||||
}
|
||||
|
||||
MethodReply MethodCall::createReply() const
|
||||
{
|
||||
sd_bus_message *sdbusReply{};
|
||||
SCOPE_EXIT{ sd_bus_message_unref(sdbusReply); }; // Returned message will become an owner of sdbusReply
|
||||
|
||||
auto r = sd_bus_message_new_method_return((sd_bus_message*)getMsg(), &sdbusReply);
|
||||
sd_bus_message* sdbusReply{};
|
||||
auto r = sdbus_->sd_bus_message_new_method_return((sd_bus_message*)msg_, &sdbusReply);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to create method reply", -r);
|
||||
|
||||
assert(sdbusReply != nullptr);
|
||||
|
||||
return MethodReply(sdbusReply);
|
||||
return MethodReply{sdbusReply, sdbus_, adopt_message};
|
||||
}
|
||||
|
||||
MethodReply MethodCall::createErrorReply(const Error& error) const
|
||||
@ -637,37 +646,33 @@ MethodReply MethodCall::createErrorReply(const Error& error) const
|
||||
SCOPE_EXIT{ sd_bus_error_free(&sdbusError); };
|
||||
sd_bus_error_set(&sdbusError, error.getName().c_str(), error.getMessage().c_str());
|
||||
|
||||
sd_bus_message *sdbusErrorReply{};
|
||||
SCOPE_EXIT{ sd_bus_message_unref(sdbusErrorReply); }; // Returned message will become an owner of sdbusErrorReply
|
||||
|
||||
auto r = sd_bus_message_new_method_error((sd_bus_message*)getMsg(), &sdbusErrorReply, &sdbusError);
|
||||
sd_bus_message* sdbusErrorReply{};
|
||||
auto r = sdbus_->sd_bus_message_new_method_error((sd_bus_message*)msg_, &sdbusErrorReply, &sdbusError);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to create method error reply", -r);
|
||||
|
||||
assert(sdbusErrorReply != nullptr);
|
||||
|
||||
return MethodReply(sdbusErrorReply);
|
||||
return MethodReply{sdbusErrorReply, sdbus_, adopt_message};
|
||||
}
|
||||
|
||||
AsyncMethodCall::AsyncMethodCall(MethodCall&& call) noexcept
|
||||
: Message(call)
|
||||
: Message(std::move(call))
|
||||
{
|
||||
}
|
||||
|
||||
void AsyncMethodCall::send(void* callback, void* userData) const
|
||||
{
|
||||
auto r = sd_bus_call_async(nullptr, nullptr, (sd_bus_message*)getMsg(), (sd_bus_message_handler_t)callback, userData, 0);
|
||||
auto r = sdbus_->sd_bus_call_async(nullptr, nullptr, (sd_bus_message*)msg_, (sd_bus_message_handler_t)callback, userData, 0);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to call method asynchronously", -r);
|
||||
}
|
||||
|
||||
void MethodReply::send() const
|
||||
{
|
||||
auto r = sd_bus_send(nullptr, (sd_bus_message*)getMsg(), nullptr);
|
||||
auto r = sdbus_->sd_bus_send(nullptr, (sd_bus_message*)msg_, nullptr);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to send reply", -r);
|
||||
}
|
||||
|
||||
void Signal::send() const
|
||||
{
|
||||
auto r = sd_bus_send(nullptr, (sd_bus_message*)getMsg(), nullptr);
|
||||
auto r = sdbus_->sd_bus_send(nullptr, (sd_bus_message*)msg_, nullptr);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to emit signal", -r);
|
||||
}
|
||||
|
||||
@ -676,16 +681,24 @@ Message createPlainMessage()
|
||||
int r;
|
||||
|
||||
sd_bus* bus{};
|
||||
SCOPE_EXIT{ sd_bus_unref(bus); }; // sdbusMsg will hold reference to the 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
|
||||
{
|
||||
BusReferenceKeeper(sd_bus* bus) : bus_(bus) {}
|
||||
~BusReferenceKeeper() { sd_bus_unref(bus_); }
|
||||
sd_bus* bus_{};
|
||||
} busReferenceKeeper{bus};
|
||||
|
||||
sd_bus_message* sdbusMsg{};
|
||||
SCOPE_EXIT{ sd_bus_message_unref(sdbusMsg); }; // Returned message will become an owner of 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(sdbusMsg);
|
||||
thread_local internal::SdBus sdbus;
|
||||
|
||||
return Message{sdbusMsg, &sdbus, adopt_message};
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,43 +0,0 @@
|
||||
/**
|
||||
* (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
*
|
||||
* @file Object.cpp
|
||||
*
|
||||
* Created on: Nov 8, 2016
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <sdbus-c++/MethodResult.h>
|
||||
#include "Object.h"
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
MethodResult::MethodResult(const MethodCall& msg, sdbus::internal::Object& object)
|
||||
: call_(msg)
|
||||
, object_(&object)
|
||||
{
|
||||
}
|
||||
|
||||
void MethodResult::send(const MethodReply& reply) const
|
||||
{
|
||||
assert(object_ != nullptr);
|
||||
object_->sendReplyAsynchronously(reply);
|
||||
}
|
||||
|
||||
}
|
@ -74,10 +74,10 @@ void Object::registerMethod( const std::string& interfaceName
|
||||
{
|
||||
SDBUS_THROW_ERROR_IF(!asyncMethodCallback, "Invalid method callback provided", EINVAL);
|
||||
|
||||
auto asyncCallback = [this, callback = std::move(asyncMethodCallback)](MethodCall& msg)
|
||||
auto asyncCallback = [callback = std::move(asyncMethodCallback)](MethodCall& msg)
|
||||
{
|
||||
MethodResult result{msg, *this};
|
||||
callback(msg, result);
|
||||
MethodResult result{msg};
|
||||
callback(std::move(msg), std::move(result));
|
||||
};
|
||||
|
||||
auto& interface = interfaces_[interfaceName];
|
||||
@ -156,17 +156,9 @@ sdbus::Signal Object::createSignal(const std::string& interfaceName, const std::
|
||||
|
||||
void Object::emitSignal(const sdbus::Signal& message)
|
||||
{
|
||||
// TODO: Make signal emitting asynchronous. Now signal can probably be emitted only from user code
|
||||
// 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)
|
||||
{
|
||||
connection_.sendReplyAsynchronously(reply);
|
||||
}
|
||||
|
||||
const std::vector<sd_bus_vtable>& Object::createInterfaceVTable(InterfaceData& interfaceData)
|
||||
{
|
||||
auto& vtable = interfaceData.vtable_;
|
||||
@ -242,9 +234,11 @@ void Object::activateInterfaceVTable( const std::string& interfaceName
|
||||
|
||||
int Object::sdbus_method_callback(sd_bus_message *sdbusMessage, void *userData, sd_bus_error *retError)
|
||||
{
|
||||
MethodCall message(sdbusMessage);
|
||||
|
||||
auto* object = static_cast<Object*>(userData);
|
||||
assert(object != nullptr);
|
||||
|
||||
MethodCall message{sdbusMessage, &object->connection_.getSdBusInterface()};
|
||||
|
||||
// Note: The lookup can be optimized by using sorted vectors instead of associative containers
|
||||
auto& callback = object->interfaces_[message.getInterfaceName()].methods_[message.getMemberName()].callback_;
|
||||
assert(callback);
|
||||
@ -269,9 +263,9 @@ int Object::sdbus_property_get_callback( sd_bus */*bus*/
|
||||
, void *userData
|
||||
, sd_bus_error *retError )
|
||||
{
|
||||
Message reply(sdbusReply);
|
||||
|
||||
auto* object = static_cast<Object*>(userData);
|
||||
assert(object != nullptr);
|
||||
|
||||
// Note: The lookup can be optimized by using sorted vectors instead of associative containers
|
||||
auto& callback = object->interfaces_[interface].properties_[property].getCallback_;
|
||||
// Getter can be empty - the case of "write-only" property
|
||||
@ -281,6 +275,8 @@ int Object::sdbus_property_get_callback( sd_bus */*bus*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
Message reply{sdbusReply, &object->connection_.getSdBusInterface()};
|
||||
|
||||
try
|
||||
{
|
||||
callback(reply);
|
||||
@ -301,13 +297,15 @@ int Object::sdbus_property_set_callback( sd_bus */*bus*/
|
||||
, void *userData
|
||||
, sd_bus_error *retError )
|
||||
{
|
||||
Message value(sdbusValue);
|
||||
|
||||
auto* object = static_cast<Object*>(userData);
|
||||
assert(object != nullptr);
|
||||
|
||||
// Note: The lookup can be optimized by using sorted vectors instead of associative containers
|
||||
auto& callback = object->interfaces_[interface].properties_[property].setCallback_;
|
||||
assert(callback);
|
||||
|
||||
Message value{sdbusValue, &object->connection_.getSdBusInterface()};
|
||||
|
||||
try
|
||||
{
|
||||
callback(value);
|
||||
|
@ -84,8 +84,6 @@ namespace internal {
|
||||
sdbus::Signal createSignal(const std::string& interfaceName, const std::string& signalName) override;
|
||||
void emitSignal(const sdbus::Signal& message) override;
|
||||
|
||||
void sendReplyAsynchronously(const MethodReply& reply);
|
||||
|
||||
private:
|
||||
using InterfaceName = std::string;
|
||||
struct InterfaceData
|
||||
|
@ -30,45 +30,40 @@
|
||||
#include "IConnection.h"
|
||||
#include <systemd/sd-bus.h>
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
namespace sdbus { namespace internal {
|
||||
|
||||
ObjectProxy::ObjectProxy(sdbus::internal::IConnection& connection, std::string destination, std::string objectPath)
|
||||
: connection_(&connection, [](sdbus::internal::IConnection *){ /* Intentionally left empty */ })
|
||||
, ownConnection_(false)
|
||||
, destination_(std::move(destination))
|
||||
, objectPath_(std::move(objectPath))
|
||||
{
|
||||
// The connection is not ours only, it is managed by the client and we just reference it here,
|
||||
// so we expect the client to manage the event loop upon this connection themselves.
|
||||
}
|
||||
|
||||
ObjectProxy::ObjectProxy( std::unique_ptr<sdbus::internal::IConnection>&& connection
|
||||
, std::string destination
|
||||
, std::string objectPath )
|
||||
: connection_(std::move(connection))
|
||||
, ownConnection_(true)
|
||||
, destination_(std::move(destination))
|
||||
, objectPath_(std::move(objectPath))
|
||||
{
|
||||
}
|
||||
|
||||
ObjectProxy::~ObjectProxy()
|
||||
{
|
||||
// If the dedicated connection for signals is used, we have to stop the processing loop
|
||||
// upon this connection prior to unregistering signal slots in the interfaces_ container,
|
||||
// otherwise we might have a race condition of two threads working upon one connection.
|
||||
if (signalConnection_ != nullptr)
|
||||
signalConnection_->leaveProcessingLoop();
|
||||
// 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.
|
||||
connection_->enterProcessingLoopAsync();
|
||||
}
|
||||
|
||||
MethodCall ObjectProxy::createMethodCall(const std::string& interfaceName, const std::string& methodName)
|
||||
{
|
||||
// Tell, don't ask
|
||||
return connection_->createMethodCall(destination_, objectPath_, interfaceName, methodName);
|
||||
}
|
||||
|
||||
AsyncMethodCall ObjectProxy::createAsyncMethodCall(const std::string& interfaceName, const std::string& methodName)
|
||||
{
|
||||
return AsyncMethodCall{createMethodCall(interfaceName, methodName)};
|
||||
return AsyncMethodCall{ObjectProxy::createMethodCall(interfaceName, methodName)};
|
||||
}
|
||||
|
||||
MethodReply ObjectProxy::callMethod(const MethodCall& message)
|
||||
@ -78,8 +73,11 @@ MethodReply ObjectProxy::callMethod(const MethodCall& message)
|
||||
|
||||
void ObjectProxy::callMethod(const AsyncMethodCall& message, async_reply_handler asyncReplyCallback)
|
||||
{
|
||||
// The new-ed handler gets deleted in the sdbus_async_reply_handler
|
||||
message.send((void*)&ObjectProxy::sdbus_async_reply_handler, new async_reply_handler(std::move(asyncReplyCallback)));
|
||||
auto callback = (void*)&ObjectProxy::sdbus_async_reply_handler;
|
||||
// Allocated userData gets deleted in the sdbus_async_reply_handler
|
||||
auto userData = new AsyncReplyUserData{*this, std::move(asyncReplyCallback)};
|
||||
|
||||
message.send(callback, userData);
|
||||
}
|
||||
|
||||
void ObjectProxy::registerSignalHandler( const std::string& interfaceName
|
||||
@ -99,30 +97,7 @@ void ObjectProxy::registerSignalHandler( const std::string& interfaceName
|
||||
|
||||
void ObjectProxy::finishRegistration()
|
||||
{
|
||||
bool hasSignals = listensToSignals();
|
||||
|
||||
if (hasSignals && ownConnection_)
|
||||
{
|
||||
// Let's use dedicated signalConnection_ for signals,
|
||||
// which will then be used by the processing loop thread.
|
||||
signalConnection_ = connection_->clone();
|
||||
registerSignalHandlers(*signalConnection_);
|
||||
signalConnection_->enterProcessingLoopAsync();
|
||||
}
|
||||
else if (hasSignals)
|
||||
{
|
||||
// Let's used connection provided from the outside.
|
||||
registerSignalHandlers(*connection_);
|
||||
}
|
||||
}
|
||||
|
||||
bool ObjectProxy::listensToSignals() const
|
||||
{
|
||||
for (auto& interfaceItem : interfaces_)
|
||||
if (!interfaceItem.second.signals_.empty())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
registerSignalHandlers(*connection_);
|
||||
}
|
||||
|
||||
void ObjectProxy::registerSignalHandlers(sdbus::internal::IConnection& connection)
|
||||
@ -149,31 +124,34 @@ void ObjectProxy::registerSignalHandlers(sdbus::internal::IConnection& connectio
|
||||
|
||||
int ObjectProxy::sdbus_async_reply_handler(sd_bus_message *sdbusMessage, void *userData, sd_bus_error *retError)
|
||||
{
|
||||
MethodReply message(sdbusMessage);
|
||||
|
||||
// We are assuming the ownership of the async reply handler pointer passed here
|
||||
std::unique_ptr<async_reply_handler> asyncReplyCallback{static_cast<async_reply_handler*>(userData)};
|
||||
assert(asyncReplyCallback != nullptr);
|
||||
std::unique_ptr<AsyncReplyUserData> asyncReplyUserData{static_cast<AsyncReplyUserData*>(userData)};
|
||||
assert(asyncReplyUserData != nullptr);
|
||||
assert(asyncReplyUserData->callback);
|
||||
|
||||
if (!sd_bus_error_is_set(retError))
|
||||
MethodReply message{sdbusMessage, &asyncReplyUserData->proxy.connection_->getSdBusInterface()};
|
||||
|
||||
const auto* error = sd_bus_message_get_error(sdbusMessage);
|
||||
if (error == nullptr)
|
||||
{
|
||||
(*asyncReplyCallback)(message, nullptr);
|
||||
asyncReplyUserData->callback(message, nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
sdbus::Error error(retError->name, retError->message);
|
||||
(*asyncReplyCallback)(message, &error);
|
||||
sdbus::Error exception(error->name, error->message);
|
||||
asyncReplyUserData->callback(message, &exception);
|
||||
}
|
||||
}
|
||||
|
||||
int ObjectProxy::sdbus_signal_callback(sd_bus_message *sdbusMessage, void *userData, sd_bus_error */*retError*/)
|
||||
{
|
||||
Signal message(sdbusMessage);
|
||||
auto* proxy = static_cast<ObjectProxy*>(userData);
|
||||
assert(proxy != nullptr);
|
||||
|
||||
Signal message{sdbusMessage, &proxy->connection_->getSdBusInterface()};
|
||||
|
||||
auto* object = static_cast<ObjectProxy*>(userData);
|
||||
assert(object != nullptr);
|
||||
// Note: The lookup can be optimized by using sorted vectors instead of associative containers
|
||||
auto& callback = object->interfaces_[message.getInterfaceName()].signals_[message.getMemberName()].callback_;
|
||||
auto& callback = proxy->interfaces_[message.getInterfaceName()].signals_[message.getMemberName()].callback_;
|
||||
assert(callback);
|
||||
|
||||
callback(message);
|
||||
|
@ -50,7 +50,6 @@ namespace internal {
|
||||
ObjectProxy( std::unique_ptr<sdbus::internal::IConnection>&& connection
|
||||
, std::string destination
|
||||
, std::string objectPath );
|
||||
~ObjectProxy() override;
|
||||
|
||||
MethodCall createMethodCall(const std::string& interfaceName, const std::string& methodName) override;
|
||||
AsyncMethodCall createAsyncMethodCall(const std::string& interfaceName, const std::string& methodName) override;
|
||||
@ -63,7 +62,12 @@ namespace internal {
|
||||
void finishRegistration() override;
|
||||
|
||||
private:
|
||||
bool listensToSignals() const;
|
||||
struct AsyncReplyUserData
|
||||
{
|
||||
ObjectProxy& proxy;
|
||||
async_reply_handler callback;
|
||||
};
|
||||
|
||||
void registerSignalHandlers(sdbus::internal::IConnection& connection);
|
||||
static int sdbus_async_reply_handler(sd_bus_message *sdbusMessage, void *userData, sd_bus_error *retError);
|
||||
static int sdbus_signal_callback(sd_bus_message *sdbusMessage, void *userData, sd_bus_error *retError);
|
||||
@ -72,8 +76,6 @@ namespace internal {
|
||||
std::unique_ptr< sdbus::internal::IConnection
|
||||
, std::function<void(sdbus::internal::IConnection*)>
|
||||
> connection_;
|
||||
bool ownConnection_{};
|
||||
std::unique_ptr<sdbus::internal::IConnection> signalConnection_;
|
||||
std::string destination_;
|
||||
std::string objectPath_;
|
||||
|
||||
|
132
src/SdBus.cpp
132
src/SdBus.cpp
@ -28,44 +28,67 @@
|
||||
|
||||
namespace sdbus { namespace internal {
|
||||
|
||||
int SdBus::sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags)
|
||||
sd_bus_message* SdBus::sd_bus_message_ref(sd_bus_message *m)
|
||||
{
|
||||
return ::sd_bus_request_name(bus, name, flags);
|
||||
}
|
||||
std::unique_lock<std::recursive_mutex> lock(sdbusMutex_);
|
||||
|
||||
int SdBus::sd_bus_release_name(sd_bus *bus, const char *name)
|
||||
{
|
||||
return ::sd_bus_release_name(bus, name);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_add_object_vtable(sd_bus *bus, sd_bus_slot **slot, const char *path, const char *interface, const sd_bus_vtable *vtable, void *userdata)
|
||||
{
|
||||
return ::sd_bus_add_object_vtable(bus, slot, path, interface, vtable, userdata);
|
||||
}
|
||||
|
||||
sd_bus_slot* SdBus::sd_bus_slot_unref(sd_bus_slot *slot)
|
||||
{
|
||||
return ::sd_bus_slot_unref(slot);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return ::sd_bus_message_new_method_call(bus, m, destination, path, interface, member);
|
||||
return ::sd_bus_message_ref(m);
|
||||
}
|
||||
|
||||
sd_bus_message* SdBus::sd_bus_message_unref(sd_bus_message *m)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_message_unref(m);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *cookie)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_send(bus, m, cookie);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_call(sd_bus *bus, sd_bus_message *m, uint64_t usec, sd_bus_error *ret_error, sd_bus_message **reply)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_call(bus, m, usec, ret_error, reply);
|
||||
}
|
||||
|
||||
int SdBus::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)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_call_async(bus, slot, m, callback, userdata, usec);
|
||||
}
|
||||
|
||||
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<std::recursive_mutex> lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_message_new_method_call(bus, m, destination, path, interface, member);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_message_new_signal(sd_bus *bus, sd_bus_message **m, const char *path, const char *interface, const char *member)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_message_new_signal(bus, m, path, interface, member);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_add_match(sd_bus *bus, sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, void *userdata)
|
||||
int SdBus::sd_bus_message_new_method_return(sd_bus_message *call, sd_bus_message **m)
|
||||
{
|
||||
return :: sd_bus_add_match(bus, slot, match, callback, userdata);
|
||||
std::unique_lock<std::recursive_mutex> lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_message_new_method_return(call, m);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_message_new_method_error(sd_bus_message *call, sd_bus_message **m, const sd_bus_error *e)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_message_new_method_error(call, m, e);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_open_user(sd_bus **ret)
|
||||
@ -78,29 +101,70 @@ int SdBus::sd_bus_open_system(sd_bus **ret)
|
||||
return ::sd_bus_open_system(ret);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_flush(sd_bus *bus)
|
||||
int SdBus::sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags)
|
||||
{
|
||||
return ::sd_bus_flush(bus);
|
||||
std::unique_lock<std::recursive_mutex> lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_request_name(bus, name, flags);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_release_name(sd_bus *bus, const char *name)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_release_name(bus, name);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_add_object_vtable(sd_bus *bus, sd_bus_slot **slot, const char *path, const char *interface, const sd_bus_vtable *vtable, void *userdata)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_add_object_vtable(bus, slot, path, interface, vtable, userdata);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_add_match(sd_bus *bus, sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, void *userdata)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(sdbusMutex_);
|
||||
|
||||
return :: sd_bus_add_match(bus, slot, match, callback, userdata);
|
||||
}
|
||||
|
||||
sd_bus_slot* SdBus::sd_bus_slot_unref(sd_bus_slot *slot)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_slot_unref(slot);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_process(sd_bus *bus, sd_bus_message **r)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_process(bus, r);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_get_fd(sd_bus *bus)
|
||||
int SdBus::sd_bus_get_poll_data(sd_bus *bus, PollData* data)
|
||||
{
|
||||
return ::sd_bus_get_fd(bus);
|
||||
std::unique_lock<std::recursive_mutex> lock(sdbusMutex_);
|
||||
|
||||
auto r = ::sd_bus_get_fd(bus);
|
||||
if (r < 0)
|
||||
return r;
|
||||
data->fd = r;
|
||||
|
||||
r = ::sd_bus_get_events(bus);
|
||||
if (r < 0)
|
||||
return r;
|
||||
data->events = static_cast<short int>(r);
|
||||
|
||||
r = ::sd_bus_get_timeout(bus, &data->timeout_usec);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_get_events(sd_bus *bus)
|
||||
int SdBus::sd_bus_flush(sd_bus *bus)
|
||||
{
|
||||
return ::sd_bus_get_events(bus);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_get_timeout(sd_bus *bus, uint64_t *timeout_usec)
|
||||
{
|
||||
return ::sd_bus_get_timeout(bus, timeout_usec);
|
||||
return ::sd_bus_flush(bus);
|
||||
}
|
||||
|
||||
sd_bus* SdBus::sd_bus_flush_close_unref(sd_bus *bus)
|
||||
|
47
src/SdBus.h
47
src/SdBus.h
@ -28,28 +28,41 @@
|
||||
#define SDBUS_CXX_SDBUS_H
|
||||
|
||||
#include "ISdBus.h"
|
||||
#include <mutex>
|
||||
|
||||
namespace sdbus { namespace internal {
|
||||
|
||||
class SdBus : public ISdBus
|
||||
class SdBus final : public ISdBus
|
||||
{
|
||||
public:
|
||||
int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags) override;
|
||||
int sd_bus_release_name(sd_bus *bus, const char *name) override;
|
||||
int sd_bus_add_object_vtable(sd_bus *bus, sd_bus_slot **slot, const char *path, const char *interface, const sd_bus_vtable *vtable, void *userdata) override;
|
||||
sd_bus_slot* sd_bus_slot_unref(sd_bus_slot *slot) override;
|
||||
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;
|
||||
sd_bus_message* sd_bus_message_unref(sd_bus_message *m) override;
|
||||
int sd_bus_message_new_signal(sd_bus *bus, sd_bus_message **m, const char *path, const char *interface, const char *member) override;
|
||||
int sd_bus_add_match(sd_bus *bus, sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, void *userdata) override;
|
||||
int sd_bus_open_user(sd_bus **ret) override;
|
||||
int sd_bus_open_system(sd_bus **ret) override;
|
||||
int sd_bus_flush(sd_bus *bus) override;
|
||||
int sd_bus_process(sd_bus *bus, sd_bus_message **r) override;
|
||||
int sd_bus_get_fd(sd_bus *bus) override;
|
||||
int sd_bus_get_events(sd_bus *bus) override;
|
||||
int sd_bus_get_timeout(sd_bus *bus, uint64_t *timeout_usec) override;
|
||||
sd_bus *sd_bus_flush_close_unref(sd_bus *bus) override;
|
||||
virtual sd_bus_message* sd_bus_message_ref(sd_bus_message *m) override;
|
||||
virtual sd_bus_message* sd_bus_message_unref(sd_bus_message *m) override;
|
||||
|
||||
virtual int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *cookie) override;
|
||||
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_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;
|
||||
virtual int sd_bus_message_new_method_error(sd_bus_message *call, sd_bus_message **m, const sd_bus_error *e) override;
|
||||
|
||||
virtual int sd_bus_open_user(sd_bus **ret) override;
|
||||
virtual int sd_bus_open_system(sd_bus **ret) override;
|
||||
virtual int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags) override;
|
||||
virtual int sd_bus_release_name(sd_bus *bus, const char *name) override;
|
||||
virtual int sd_bus_add_object_vtable(sd_bus *bus, sd_bus_slot **slot, const char *path, const char *interface, const sd_bus_vtable *vtable, void *userdata) override;
|
||||
virtual int sd_bus_add_match(sd_bus *bus, sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, void *userdata) override;
|
||||
virtual sd_bus_slot* sd_bus_slot_unref(sd_bus_slot *slot) override;
|
||||
|
||||
virtual int sd_bus_process(sd_bus *bus, sd_bus_message **r) override;
|
||||
virtual int sd_bus_get_poll_data(sd_bus *bus, PollData* data) override;
|
||||
|
||||
virtual int sd_bus_flush(sd_bus *bus) override;
|
||||
virtual sd_bus *sd_bus_flush_close_unref(sd_bus *bus) override;
|
||||
|
||||
private:
|
||||
std::recursive_mutex sdbusMutex_;
|
||||
};
|
||||
|
||||
}}
|
||||
|
@ -29,7 +29,7 @@
|
||||
#include <systemd/sd-bus.h>
|
||||
#include <cassert>
|
||||
|
||||
namespace sdbus { /*namespace internal {*/
|
||||
namespace sdbus {
|
||||
|
||||
Variant::Variant()
|
||||
: msg_(createPlainMessage())
|
||||
|
@ -201,7 +201,7 @@ std::tuple<std::string, std::string> AdaptorGenerator::processMethods(const Node
|
||||
Nodes outArgs = args.select("direction" , "out");
|
||||
|
||||
std::string argStr, argTypeStr;
|
||||
std::tie(argStr, argTypeStr, std::ignore) = argsToNamesAndTypes(inArgs);
|
||||
std::tie(argStr, argTypeStr, std::ignore) = argsToNamesAndTypes(inArgs, async);
|
||||
|
||||
using namespace std::string_literals;
|
||||
|
||||
@ -210,7 +210,7 @@ std::tuple<std::string, std::string> AdaptorGenerator::processMethods(const Node
|
||||
<< ".onInterface(interfaceName)"
|
||||
<< ".implementedAs("
|
||||
<< "[this]("
|
||||
<< (async ? "sdbus::Result<" + outArgsToType(outArgs, true) + "> result" + (argTypeStr.empty() ? "" : ", ") : "")
|
||||
<< (async ? "sdbus::Result<" + outArgsToType(outArgs, true) + ">&& result" + (argTypeStr.empty() ? "" : ", ") : "")
|
||||
<< argTypeStr
|
||||
<< "){ " << (async ? "" : "return ") << "this->" << methodName << "("
|
||||
<< (async ? "std::move(result)"s + (argTypeStr.empty() ? "" : ", ") : "")
|
||||
@ -222,7 +222,7 @@ std::tuple<std::string, std::string> AdaptorGenerator::processMethods(const Node
|
||||
<< (async ? "void" : outArgsToType(outArgs))
|
||||
<< " " << methodName
|
||||
<< "("
|
||||
<< (async ? "sdbus::Result<" + outArgsToType(outArgs, true) + "> result" + (argTypeStr.empty() ? "" : ", ") : "")
|
||||
<< (async ? "sdbus::Result<" + outArgsToType(outArgs, true) + ">&& result" + (argTypeStr.empty() ? "" : ", ") : "")
|
||||
<< argTypeStr
|
||||
<< ") = 0;" << endl;
|
||||
}
|
||||
|
@ -104,7 +104,7 @@ std::tuple<unsigned, std::string> BaseGenerator::generateNamespaces(const std::s
|
||||
}
|
||||
|
||||
|
||||
std::tuple<std::string, std::string, std::string> BaseGenerator::argsToNamesAndTypes(const Nodes& args) const
|
||||
std::tuple<std::string, std::string, std::string> BaseGenerator::argsToNamesAndTypes(const Nodes& args, bool async) const
|
||||
{
|
||||
std::ostringstream argSS, argTypeSS, typeSS;
|
||||
|
||||
@ -124,8 +124,16 @@ std::tuple<std::string, std::string, std::string> BaseGenerator::argsToNamesAndT
|
||||
argName = "arg" + std::to_string(i);
|
||||
}
|
||||
auto type = signature_to_type(arg->get("type"));
|
||||
argSS << argName;
|
||||
argTypeSS << "const " << type << "& " << argName;
|
||||
if (!async)
|
||||
{
|
||||
argSS << argName;
|
||||
argTypeSS << "const " << type << "& " << argName;
|
||||
}
|
||||
else
|
||||
{
|
||||
argSS << "std::move(" << argName << ")";
|
||||
argTypeSS << type << " " << argName;
|
||||
}
|
||||
typeSS << type;
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,7 @@ protected:
|
||||
* @param args
|
||||
* @return tuple: argument names, argument types and names, argument types
|
||||
*/
|
||||
std::tuple<std::string, std::string, std::string> argsToNamesAndTypes(const sdbuscpp::xml::Nodes& args) const;
|
||||
std::tuple<std::string, std::string, std::string> argsToNamesAndTypes(const sdbuscpp::xml::Nodes& args, bool async = false) const;
|
||||
|
||||
/**
|
||||
* Output arguments to return type
|
||||
|
@ -90,7 +90,6 @@ public:
|
||||
};
|
||||
|
||||
std::unique_ptr<sdbus::IConnection> AdaptorAndProxyFixture::s_connection = sdbus::createSystemBusConnection();
|
||||
|
||||
}
|
||||
|
||||
/*-------------------------------------*/
|
||||
|
@ -45,7 +45,7 @@ public:
|
||||
|
||||
protected:
|
||||
|
||||
void noArgNoReturn() const { }
|
||||
void noArgNoReturn() const {}
|
||||
|
||||
int32_t getInt() const { return INT32_VALUE; }
|
||||
|
||||
|
@ -48,11 +48,11 @@ protected:
|
||||
{
|
||||
static unsigned int counter = 0;
|
||||
static std::chrono::time_point<std::chrono::steady_clock> startTime;
|
||||
|
||||
|
||||
assert(data.size() == m_msgSize);
|
||||
|
||||
|
||||
++counter;
|
||||
|
||||
|
||||
if (counter == 1)
|
||||
startTime = std::chrono::steady_clock::now();
|
||||
else if (counter == m_msgCount)
|
||||
@ -62,7 +62,7 @@ protected:
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
unsigned int m_msgSize{};
|
||||
unsigned int m_msgCount{};
|
||||
@ -95,68 +95,68 @@ int main(int /*argc*/, char */*argv*/[])
|
||||
const unsigned int repetitions{20};
|
||||
unsigned int msgCount = 1000;
|
||||
unsigned int msgSize{};
|
||||
|
||||
|
||||
msgSize = 20;
|
||||
std::cout << "** Measuring signals of size " << msgSize << " bytes (" << repetitions << " repetitions)..." << std::endl << std::endl;
|
||||
client.m_msgCount = msgCount; client.m_msgSize = msgSize;
|
||||
for (unsigned int r = 0; r < repetitions; ++r)
|
||||
{
|
||||
client.sendDataSignals(msgCount, msgSize);
|
||||
|
||||
|
||||
std::this_thread::sleep_for(1000ms);
|
||||
}
|
||||
|
||||
|
||||
msgSize = 1000;
|
||||
std::cout << std::endl << "** Measuring signals of size " << msgSize << " bytes (" << repetitions << " repetitions)..." << std::endl << std::endl;
|
||||
client.m_msgCount = msgCount; client.m_msgSize = msgSize;
|
||||
for (unsigned int r = 0; r < repetitions; ++r)
|
||||
{
|
||||
client.sendDataSignals(msgCount, msgSize);
|
||||
|
||||
|
||||
std::this_thread::sleep_for(1000ms);
|
||||
}
|
||||
|
||||
|
||||
msgSize = 20;
|
||||
std::cout << std::endl << "** Measuring method calls of size " << msgSize << " bytes (" << repetitions << " repetitions)..." << std::endl << std::endl;
|
||||
for (unsigned int r = 0; r < repetitions; ++r)
|
||||
{
|
||||
auto str1 = createRandomString(msgSize/2);
|
||||
auto str2 = createRandomString(msgSize/2);
|
||||
|
||||
|
||||
auto startTime = std::chrono::steady_clock::now();
|
||||
for (unsigned int i = 0; i < msgCount; i++)
|
||||
{
|
||||
auto result = client.concatenateTwoStrings(str1, str2);
|
||||
|
||||
|
||||
assert(result.size() == str1.size() + str2.size());
|
||||
assert(result.size() == msgSize);
|
||||
}
|
||||
auto stopTime = std::chrono::steady_clock::now();
|
||||
std::cout << "Called " << msgCount << " methods in: " << std::chrono::duration_cast<std::chrono::milliseconds>(stopTime - startTime).count() << " ms" << std::endl;
|
||||
|
||||
|
||||
std::this_thread::sleep_for(1000ms);
|
||||
}
|
||||
|
||||
|
||||
msgSize = 1000;
|
||||
std::cout << std::endl << "** Measuring method calls of size " << msgSize << " bytes (" << repetitions << " repetitions)..." << std::endl << std::endl;
|
||||
for (unsigned int r = 0; r < repetitions; ++r)
|
||||
{
|
||||
auto str1 = createRandomString(msgSize/2);
|
||||
auto str2 = createRandomString(msgSize/2);
|
||||
|
||||
|
||||
auto startTime = std::chrono::steady_clock::now();
|
||||
for (unsigned int i = 0; i < msgCount; i++)
|
||||
{
|
||||
auto result = client.concatenateTwoStrings(str1, str2);
|
||||
|
||||
|
||||
assert(result.size() == str1.size() + str2.size());
|
||||
assert(result.size() == msgSize);
|
||||
}
|
||||
auto stopTime = std::chrono::steady_clock::now();
|
||||
std::cout << "Called " << msgCount << " methods in: " << std::chrono::duration_cast<std::chrono::milliseconds>(stopTime - startTime).count() << " ms" << std::endl;
|
||||
|
||||
|
||||
std::this_thread::sleep_for(1000ms);
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -34,21 +34,30 @@
|
||||
class SdBusMock : public sdbus::internal::ISdBus
|
||||
{
|
||||
public:
|
||||
MOCK_METHOD1(sd_bus_message_ref, sd_bus_message*(sd_bus_message *m));
|
||||
MOCK_METHOD1(sd_bus_message_unref, sd_bus_message*(sd_bus_message *m));
|
||||
|
||||
MOCK_METHOD3(sd_bus_send, int(sd_bus *bus, sd_bus_message *m, uint64_t *cookie));
|
||||
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_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));
|
||||
MOCK_METHOD3(sd_bus_message_new_method_error, int(sd_bus_message *call, sd_bus_message **m, const sd_bus_error *e));
|
||||
|
||||
MOCK_METHOD1(sd_bus_open_user, int(sd_bus **ret));
|
||||
MOCK_METHOD1(sd_bus_open_system, int(sd_bus **ret));
|
||||
MOCK_METHOD3(sd_bus_request_name, int(sd_bus *bus, const char *name, uint64_t flags));
|
||||
MOCK_METHOD2(sd_bus_release_name, int(sd_bus *bus, const char *name));
|
||||
MOCK_METHOD6(sd_bus_add_object_vtable, int(sd_bus *bus, sd_bus_slot **slot, const char *path, const char *interface, const sd_bus_vtable *vtable, void *userdata));
|
||||
MOCK_METHOD1(sd_bus_slot_unref, sd_bus_slot*(sd_bus_slot *slot));
|
||||
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_METHOD1(sd_bus_message_unref, sd_bus_message* (sd_bus_message *m));
|
||||
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_METHOD5(sd_bus_add_match, int(sd_bus *bus, sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, void *userdata));
|
||||
MOCK_METHOD1(sd_bus_open_user, int(sd_bus **ret));
|
||||
MOCK_METHOD1(sd_bus_open_system, int(sd_bus **ret));
|
||||
MOCK_METHOD1(sd_bus_flush, int(sd_bus *bus));
|
||||
MOCK_METHOD1(sd_bus_slot_unref, sd_bus_slot*(sd_bus_slot *slot));
|
||||
|
||||
MOCK_METHOD2(sd_bus_process, int(sd_bus *bus, sd_bus_message **r));
|
||||
MOCK_METHOD1(sd_bus_get_fd, int(sd_bus *bus));
|
||||
MOCK_METHOD1(sd_bus_get_events, int(sd_bus *bus));
|
||||
MOCK_METHOD2(sd_bus_get_timeout, int(sd_bus *bus, uint64_t *timeout_usec));
|
||||
MOCK_METHOD2(sd_bus_get_poll_data, int(sd_bus *bus, PollData* data));
|
||||
|
||||
MOCK_METHOD1(sd_bus_flush, int(sd_bus *bus));
|
||||
MOCK_METHOD1(sd_bus_flush_close_unref, sd_bus *(sd_bus *bus));
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user