forked from Kistler-Group/sdbus-cpp
refactor: simplify async D-Bus connection handling
This commit is contained in:
committed by
Stanislav Angelovič
parent
7450515d0b
commit
3e20fc639e
@@ -51,62 +51,7 @@ namespace sdbus {
|
||||
class IConnection
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* Poll Data for external event loop implementations.
|
||||
*
|
||||
* To integrate sdbus with your app's own custom event handling system
|
||||
* you can use this method to query which file descriptors, poll events
|
||||
* and timeouts you should add to your app's poll(2), or select(2)
|
||||
* call in your main event loop.
|
||||
*
|
||||
* If you are unsure what this all means then use
|
||||
* enterEventLoop() or enterEventLoopAsync() instead.
|
||||
*
|
||||
* See: getEventLoopPollData()
|
||||
*/
|
||||
struct PollData
|
||||
{
|
||||
/*!
|
||||
* The read fd to be monitored by the event loop.
|
||||
*/
|
||||
int fd;
|
||||
/*!
|
||||
* The events to use for poll(2) alongside fd.
|
||||
*/
|
||||
short int events;
|
||||
|
||||
/*!
|
||||
* Absolute timeout value in micro seconds and based of CLOCK_MONOTONIC.
|
||||
*/
|
||||
uint64_t timeout_usec;
|
||||
|
||||
/*!
|
||||
* Get the event poll timeout.
|
||||
*
|
||||
* The timeout is an absolute value based of CLOCK_MONOTONIC.
|
||||
*
|
||||
* @return a duration since the CLOCK_MONOTONIC epoch started.
|
||||
*/
|
||||
[[nodiscard]] std::chrono::microseconds getAbsoluteTimeout() const
|
||||
{
|
||||
return std::chrono::microseconds(timeout_usec);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Get the timeout as relative value from now
|
||||
*
|
||||
* @return std::nullopt if the timeout is indefinite. A duration otherwise.
|
||||
*/
|
||||
[[nodiscard]] std::optional<std::chrono::microseconds> getRelativeTimeout() const;
|
||||
|
||||
/*!
|
||||
* Get a converted, relative timeout which can be passed as argument 'timeout' to poll(2)
|
||||
*
|
||||
* @return -1 if the timeout is indefinite. 0 if the poll(2) shouldn't block. An integer in milli
|
||||
* seconds otherwise.
|
||||
*/
|
||||
[[nodiscard]] int getPollTimeout() const;
|
||||
};
|
||||
struct PollData;
|
||||
|
||||
virtual ~IConnection() = default;
|
||||
|
||||
@@ -129,7 +74,7 @@ namespace sdbus {
|
||||
virtual void releaseName(const std::string& name) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Retrieve the unique name of a connection. E.g. ":1.xx"
|
||||
* @brief Retrieves the unique name of a connection. E.g. ":1.xx"
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
@@ -180,44 +125,57 @@ namespace sdbus {
|
||||
[[deprecated("Use one of other addObjectManager overloads")]] virtual void addObjectManager(const std::string& objectPath) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Returns fd, I/O events and timeout data you can pass to poll
|
||||
* @brief Returns fd's, I/O events and timeout data to be used in an external event loop
|
||||
*
|
||||
* To integrate sdbus with your app's own custom event handling system
|
||||
* (without the requirement of an extra thread), you can use this
|
||||
* method to query which file descriptors, poll events and timeouts you
|
||||
* should add to your app's poll call in your main event loop. If these
|
||||
* file descriptors signal, then you should call processPendingRequest
|
||||
* to process the event. This means that all of sdbus's callbacks will
|
||||
* arrive on your app's main event thread (opposed to on a thread created
|
||||
* by sdbus-c++). If you are unsure what this all means then use
|
||||
* enterEventLoop() or enterEventLoopAsync() instead.
|
||||
* This function is useful to hook up a bus connection object with an
|
||||
* external (like GMainLoop, boost::asio, etc.) or manual event loop
|
||||
* involving poll() or a similar I/O polling call.
|
||||
*
|
||||
* To integrate sdbus-c++ into a gtk app, pass the file descriptor returned
|
||||
* by this method to g_main_context_add_poll.
|
||||
* Before **each** invocation of the I/O polling call, this function
|
||||
* should be invoked. Returned PollData::fd file descriptor should
|
||||
* be polled for the events indicated by PollData::events, and the I/O
|
||||
* call should block for that up to the returned PollData::timeout.
|
||||
*
|
||||
* Additionally, returned PollData::eventFd should be polled for POLLIN
|
||||
* events.
|
||||
*
|
||||
* After each I/O polling call the bus connection needs to process
|
||||
* incoming or outgoing data, by invoking processPendingEvent().
|
||||
*
|
||||
* Note that the returned timeout should be considered only a maximum
|
||||
* sleeping time. It is permissible (and even expected) that shorter
|
||||
* timeouts are used by the calling program, in case other event sources
|
||||
* are polled in the same event loop. Note that the returned time-value
|
||||
* is absolute, based of CLOCK_MONOTONIC and specified in microseconds.
|
||||
* Use PollData::getPollTimeout() to have the timeout value converted
|
||||
* in a form that can be passed to poll(2).
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual PollData getEventLoopPollData() const = 0;
|
||||
[[nodiscard]] virtual PollData getEventLoopPollData() const = 0;
|
||||
|
||||
/*!
|
||||
* @brief Process a pending request
|
||||
* @brief Processes a pending event
|
||||
*
|
||||
* @returns true if an event was processed, false if poll should be called
|
||||
* @returns True if an event was processed, false if no operations were pending
|
||||
*
|
||||
* Processes a single dbus event. All of sdbus-c++'s callbacks will be called
|
||||
* from within this method. This method should ONLY be used in conjuction
|
||||
* with getEventLoopPollData().
|
||||
* This method returns true if an I/O message was processed. This you can try
|
||||
* to call this method again before going to poll on I/O events. The method
|
||||
* returns false if no operations were pending, and the caller should then
|
||||
* poll for I/O events before calling this method again.
|
||||
* enterEventLoop() and enterEventLoopAsync() will call this method for you,
|
||||
* so there is no need to call it when using these. If you are unsure what
|
||||
* this all means then don't use this method.
|
||||
* This function drives the D-Bus connection. It processes pending I/O events.
|
||||
* Queued outgoing messages (or parts thereof) are sent out. Queued incoming
|
||||
* messages are dispatched to registered callbacks. Timeouts are recalculated.
|
||||
*
|
||||
* It returns false when no operations were pending and true if a message was
|
||||
* processed. When false is returned the caller should synchronously poll for
|
||||
* I/O events before calling into processPendingEvent() again.
|
||||
* Don't forget to call getEventLoopPollData() each time before the next poll.
|
||||
*
|
||||
* You don't need to directly call this method or getEventLoopPollData() method
|
||||
* when using convenient, internal bus connection event loops through
|
||||
* enterEventLoop() or enterEventLoopAsync() calls.
|
||||
* It is invoked automatically when necessary.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual bool processPendingRequest() = 0;
|
||||
virtual bool processPendingEvent() = 0;
|
||||
|
||||
/*!
|
||||
* @brief Sets general method call timeout
|
||||
@@ -373,6 +331,55 @@ namespace sdbus {
|
||||
* @deprecated This function has been replaced by getEventLoopPollData()
|
||||
*/
|
||||
[[deprecated("This function has been replaced by getEventLoopPollData()")]] PollData getProcessLoopPollData() const;
|
||||
|
||||
/*!
|
||||
* @struct PollData
|
||||
*
|
||||
* Carries poll data needed for integration with external event loop implementations.
|
||||
*
|
||||
* See getEventLoopPollData() for more info.
|
||||
*/
|
||||
struct PollData
|
||||
{
|
||||
/*!
|
||||
* The read fd to be monitored by the event loop.
|
||||
*/
|
||||
int fd;
|
||||
|
||||
/*!
|
||||
* The events to use for poll(2) alongside fd.
|
||||
*/
|
||||
short int events;
|
||||
|
||||
/*!
|
||||
* Absolute timeout value in microseconds, based of CLOCK_MONOTONIC.
|
||||
*
|
||||
* Call getPollTimeout() to get timeout recalculated to relative timeout that can be passed to poll(2).
|
||||
*/
|
||||
std::chrono::microseconds timeout;
|
||||
|
||||
/*!
|
||||
* An additional event fd to be monitored by the event loop for POLLIN events.
|
||||
*/
|
||||
int eventFd;
|
||||
|
||||
/*!
|
||||
* Returns the timeout as relative value from now.
|
||||
*
|
||||
* Returned value is std::chrono::microseconds::max() if the timeout is indefinite.
|
||||
*
|
||||
* @return Relative timeout as a time duration
|
||||
*/
|
||||
[[nodiscard]] std::chrono::microseconds getRelativeTimeout() const;
|
||||
|
||||
/*!
|
||||
* Returns relative timeout in the form which can be passed as argument 'timeout' to poll(2)
|
||||
*
|
||||
* @return -1 if the timeout is indefinite. 0 if the poll(2) shouldn't block.
|
||||
* An integer in milliseconds otherwise.
|
||||
*/
|
||||
[[nodiscard]] int getPollTimeout() const;
|
||||
};
|
||||
};
|
||||
|
||||
template <typename _Rep, typename _Period>
|
||||
|
||||
+19
-10
@@ -83,20 +83,29 @@ namespace sdbus {
|
||||
virtual MethodCall createMethodCall(const std::string& interfaceName, const std::string& methodName) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Calls method on the D-Bus object
|
||||
* @brief Calls method on the remote D-Bus object
|
||||
*
|
||||
* @param[in] message Message representing a method call
|
||||
* @param[in] timeout Timeout for dbus call in microseconds
|
||||
* @return A method reply message
|
||||
*
|
||||
* Normally, the call is blocking, i.e. it waits for the remote method to finish with either
|
||||
* a return value or an error.
|
||||
* The call does not block if the method call has dont-expect-reply flag set. In that case,
|
||||
* the call returns immediately and the return value is an empty, invalid method reply.
|
||||
*
|
||||
* If the method call argument is set to not expect reply, the call will not wait for the remote
|
||||
* method to finish, i.e. the call will be non-blocking, and the function will return an empty,
|
||||
* invalid MethodReply object (representing void).
|
||||
* The call blocks otherwise, waiting for the remote peer to send back a reply, or an error,
|
||||
* or until the call times out.
|
||||
*
|
||||
* Note: To avoid messing with messages, use higher-level API defined below.
|
||||
* While blocking, other concurrent operations (in other threads) on the underlying bus
|
||||
* connection are stalled until the call returns. This is not an issue in vast majority of
|
||||
* (simple, single-threaded) applications. In asynchronous, multi-threaded designs involving
|
||||
* shared bus connections, this may be an issue. It is advised to instead use an asynchronous
|
||||
* callMethod() function overload, which does not block the bus connection, or do the synchronous
|
||||
* call from another Proxy instance created just before the call and then destroyed (which is
|
||||
* anyway quite a typical approach in D-Bus implementations). Such proxy instance must have
|
||||
* its own bus connection. Slim proxies created with `dont_run_event_loop_thread` tag are
|
||||
* designed for exactly that purpose.
|
||||
*
|
||||
* Note: To avoid messing with messages, use API on a higher level of abstraction defined below.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
@@ -117,10 +126,10 @@ namespace sdbus {
|
||||
* @return Cookie for the the pending asynchronous call
|
||||
*
|
||||
* The call is non-blocking. It doesn't wait for the reply. Once the reply arrives,
|
||||
* the provided async reply handler will get invoked from the context of the connection
|
||||
* I/O event loop thread.
|
||||
* the provided async reply handler will get invoked from the context of the bus
|
||||
* connection I/O event loop thread.
|
||||
*
|
||||
* Note: To avoid messing with messages, use higher-level API defined below.
|
||||
* Note: To avoid messing with messages, use API on a higher level of abstraction defined below.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
|
||||
@@ -56,7 +56,6 @@ namespace sdbus {
|
||||
class MethodReply;
|
||||
namespace internal {
|
||||
class ISdBus;
|
||||
class IConnection;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,12 +257,11 @@ namespace sdbus {
|
||||
bool doesntExpectReply() const;
|
||||
|
||||
protected:
|
||||
MethodCall(void *msg, internal::ISdBus* sdbus, const internal::IConnection* connection, adopt_message_t) noexcept;
|
||||
MethodCall(void *msg, internal::ISdBus* sdbus, adopt_message_t) noexcept;
|
||||
|
||||
private:
|
||||
MethodReply sendWithReply(uint64_t timeout = 0) const;
|
||||
MethodReply sendWithNoReply() const;
|
||||
const internal::IConnection* connection_{};
|
||||
};
|
||||
|
||||
class MethodReply : public Message
|
||||
|
||||
Reference in New Issue
Block a user