From patchwork Wed Jan 23 08:59:22 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 347 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C811F60C9C for ; Wed, 23 Jan 2019 09:59:29 +0100 (CET) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 5824623E for ; Wed, 23 Jan 2019 09:59:29 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1548233969; bh=jGwEGD2Js39ZX+865l7YI72a5zJN+1GNZuOluD2WQac=; h=From:To:Subject:Date:In-Reply-To:References:From; b=jlwf+XRUlAImna14Y53dQFK8YvhZNkq1sPPWFDvQSOqQM0tVQnw+AoUiiqxp3yV4y Rfc1v6KhELT3pfRWZX9xZZDQ5p240zEFfG3ov/ZfaMmA+0p/MzHLQxAsy0WEMibyA8 v6jHbynKp95y6EDcgPhGklPH4UiwuwUZY+ot2tug= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Wed, 23 Jan 2019 10:59:22 +0200 Message-Id: <20190123085923.12524-4-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20190123085923.12524-1-laurent.pinchart@ideasonboard.com> References: <20190123085923.12524-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 3/4] libcamera: event_dispatcher: Add interrupt() function X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 23 Jan 2019 08:59:30 -0000 The new interrupt() function allows interrupting in-progress blocking processEvents() calls. This is useful to stop running event loops. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- include/libcamera/event_dispatcher.h | 2 ++ src/libcamera/event_dispatcher.cpp | 10 ++++++ src/libcamera/event_dispatcher_poll.cpp | 32 ++++++++++++++++++- src/libcamera/include/event_dispatcher_poll.h | 3 ++ 4 files changed, 46 insertions(+), 1 deletion(-) diff --git a/include/libcamera/event_dispatcher.h b/include/libcamera/event_dispatcher.h index c20518c6866d..cb06bf208e12 100644 --- a/include/libcamera/event_dispatcher.h +++ b/include/libcamera/event_dispatcher.h @@ -26,6 +26,8 @@ public: virtual void unregisterTimer(Timer *timer) = 0; virtual void processEvents() = 0; + + virtual void interrupt() = 0; }; } /* namespace libcamera */ diff --git a/src/libcamera/event_dispatcher.cpp b/src/libcamera/event_dispatcher.cpp index f7c40734095e..b82c59c3f5dc 100644 --- a/src/libcamera/event_dispatcher.cpp +++ b/src/libcamera/event_dispatcher.cpp @@ -104,4 +104,14 @@ EventDispatcher::~EventDispatcher() * it before returning. */ +/** + * \fn EventDispatcher::interrupt() + * \brief Interrupt any running processEvents() call as soon as possible + * + * Calling this function interrupts any blocking processEvents() call in + * progress. The processEvents() function will return as soon as possible, + * after processing pending timers and events. If processEvents() isn't in + * progress, it will be interrupted immediately the next time it gets called. + */ + } /* namespace libcamera */ diff --git a/src/libcamera/event_dispatcher_poll.cpp b/src/libcamera/event_dispatcher_poll.cpp index 6e0609c34ddc..a2674ab31135 100644 --- a/src/libcamera/event_dispatcher_poll.cpp +++ b/src/libcamera/event_dispatcher_poll.cpp @@ -8,7 +8,10 @@ #include #include #include +#include #include +#include +#include #include #include @@ -43,10 +46,18 @@ static const char *notifierType(EventNotifier::Type type) EventDispatcherPoll::EventDispatcherPoll() { + /* + * Create the event fd. Failures are fatal as we can't implement an + * interruptible dispatcher without the fd. + */ + eventfd_ = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); + if (eventfd_ < 0) + LOG(Event, Fatal) << "Unable to create eventfd"; } EventDispatcherPoll::~EventDispatcherPoll() { + close(eventfd_); } void EventDispatcherPoll::registerEventNotifier(EventNotifier *notifier) @@ -123,11 +134,13 @@ void EventDispatcherPoll::processEvents() /* Create the pollfd array. */ std::vector pollfds; - pollfds.reserve(notifiers_.size()); + pollfds.reserve(notifiers_.size() + 1); for (auto notifier : notifiers_) pollfds.push_back({ notifier.first, notifier.second.events(), 0 }); + pollfds.push_back({ eventfd_, POLLIN, 0 }); + /* Wait for events and process notifiers and timers. */ do { ret = poll(&pollfds); @@ -137,12 +150,20 @@ void EventDispatcherPoll::processEvents() ret = -errno; LOG(Event, Warning) << "poll() failed with " << strerror(-ret); } else if (ret > 0) { + processInterrupt(pollfds.back()); + pollfds.pop_back(); processNotifiers(pollfds); } processTimers(); } +void EventDispatcherPoll::interrupt() +{ + uint64_t value = 1; + write(eventfd_, &value, sizeof(value)); +} + short EventDispatcherPoll::EventNotifierSetPoll::events() const { short events = 0; @@ -186,6 +207,15 @@ int EventDispatcherPoll::poll(std::vector *pollfds) nextTimer ? &timeout : nullptr, nullptr); } +void EventDispatcherPoll::processInterrupt(const struct pollfd &pfd) +{ + if (!pfd.revents & POLLIN) + return; + + uint64_t value; + read(eventfd_, &value, sizeof(value)); +} + void EventDispatcherPoll::processNotifiers(const std::vector &pollfds) { static const struct { diff --git a/src/libcamera/include/event_dispatcher_poll.h b/src/libcamera/include/event_dispatcher_poll.h index ac3efde082b4..1c0066c24dc8 100644 --- a/src/libcamera/include/event_dispatcher_poll.h +++ b/src/libcamera/include/event_dispatcher_poll.h @@ -31,6 +31,7 @@ public: void unregisterTimer(Timer *timer); void processEvents(); + void interrupt(); private: struct EventNotifierSetPoll { @@ -40,8 +41,10 @@ private: std::map notifiers_; std::list timers_; + int eventfd_; int poll(std::vector *pollfds); + void processInterrupt(const struct pollfd &pfd); void processNotifiers(const std::vector &pollfds); void processTimers(); };