From 0440dcb15b5e363071f7964e9617c4f6e8698780 Mon Sep 17 00:00:00 2001 From: hogliux Date: Tue, 8 Oct 2019 18:59:56 +0100 Subject: [PATCH] Added ability to integrate with foreign event loops --- include/sdbus-c++/IConnection.h | 42 +++++++++++++++++++++++++++++++++ src/Connection.cpp | 21 +++++++++++++---- src/Connection.h | 3 ++- 3 files changed, 60 insertions(+), 6 deletions(-) diff --git a/include/sdbus-c++/IConnection.h b/include/sdbus-c++/IConnection.h index 5dce024..7f9fbc4 100644 --- a/include/sdbus-c++/IConnection.h +++ b/include/sdbus-c++/IConnection.h @@ -46,6 +46,13 @@ namespace sdbus { class IConnection { public: + struct PollData + { + int fd; + short int events; + uint64_t timeout_usec; + }; + virtual ~IConnection() = default; /*! @@ -103,6 +110,41 @@ namespace sdbus { * @throws sdbus::Error in case of failure */ virtual void addObjectManager(const std::string& objectPath) = 0; + + /*! + * @brief Returns parameters you can pass to poll + * + * 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 + * enterProcessingLoop() or enterProcessingLoopAsync() instead. + * + * To integrate sdbus-c++ into a gtk app, pass the file descriptor returned + * by this method to g_main_context_add_poll. + * + * @throws sdbus::Error in case of failure + */ + virtual PollData getProcessLoopPollData() = 0; + + /*! + * @brief Process a pending request + * + * 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 getProcessLoopPollData(). enterProcessingLoop() and + * enterProcessingLoopAsync() 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. + * + * @returns true if an event was processed + * @throws sdbus::Error in case of failure + */ + virtual bool processPendingRequest() = 0; }; /*! diff --git a/src/Connection.cpp b/src/Connection.cpp index 3a72d21..6679073 100644 --- a/src/Connection.cpp +++ b/src/Connection.cpp @@ -108,6 +108,20 @@ void Connection::leaveProcessingLoop() joinWithProcessingLoop(); } +sdbus::IConnection::PollData Connection::getProcessLoopPollData() +{ + sdbus::IConnection::PollData pollData; + ISdBus::PollData sdbusPollData; + auto r = iface_->sd_bus_get_poll_data(bus_.get(), &sdbusPollData); + SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus poll data", -r); + + pollData.fd = sdbusPollData.fd; + pollData.events = sdbusPollData.events; + pollData.timeout_usec = sdbusPollData.timeout_usec; + + return pollData; +} + const ISdBus& Connection::getSdBusInterface() const { return *iface_.get(); @@ -345,15 +359,12 @@ bool Connection::waitForNextRequest() assert(bus != nullptr); assert(loopExitFd_ != 0); - 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); - + auto sdbusPollData = getProcessLoopPollData(); struct pollfd fds[] = {{sdbusPollData.fd, sdbusPollData.events, 0}, {loopExitFd_, POLLIN, 0}}; auto fdsCount = sizeof(fds)/sizeof(fds[0]); auto timeout = sdbusPollData.timeout_usec == (uint64_t) -1 ? (uint64_t)-1 : (sdbusPollData.timeout_usec+999)/1000; - r = poll(fds, fdsCount, timeout); + auto r = poll(fds, fdsCount, timeout); if (r < 0 && errno == EINTR) return true; // Try again diff --git a/src/Connection.h b/src/Connection.h index 00c9ace..ee542ff 100644 --- a/src/Connection.h +++ b/src/Connection.h @@ -57,6 +57,8 @@ namespace sdbus { namespace internal { void enterProcessingLoop() override; void enterProcessingLoopAsync() override; void leaveProcessingLoop() override; + bool processPendingRequest() override; + sdbus::IConnection::PollData getProcessLoopPollData() override; void addObjectManager(const std::string& objectPath) override; SlotPtr addObjectManager(const std::string& objectPath, void* /*dummy*/) override; @@ -99,7 +101,6 @@ namespace sdbus { namespace internal { void finishHandshake(sd_bus* bus); static int createProcessingLoopExitDescriptor(); static void closeProcessingLoopExitDescriptor(int fd); - bool processPendingRequest(); bool waitForNextRequest(); static std::string composeSignalMatchFilter( const std::string& objectPath , const std::string& interfaceName