From 4d470eb37fe31cc9899ee36e81134b35b02a36f3 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 23 Jan 2019 10:04:23 +0200 Subject: libcamera: event_dispatcher: Add interrupt() function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Reviewed-by: Niklas Söderlund --- src/libcamera/event_dispatcher_poll.cpp | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) (limited to 'src/libcamera/event_dispatcher_poll.cpp') diff --git a/src/libcamera/event_dispatcher_poll.cpp b/src/libcamera/event_dispatcher_poll.cpp index 6e0609c3..a2674ab3 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 { -- cgit v1.2.1