diff options
-rw-r--r-- | include/libcamera/event_dispatcher.h | 2 | ||||
-rw-r--r-- | src/libcamera/event_dispatcher.cpp | 10 | ||||
-rw-r--r-- | src/libcamera/event_dispatcher_poll.cpp | 32 | ||||
-rw-r--r-- | src/libcamera/include/event_dispatcher_poll.h | 3 |
4 files changed, 46 insertions, 1 deletions
diff --git a/include/libcamera/event_dispatcher.h b/include/libcamera/event_dispatcher.h index c20518c6..cb06bf20 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 f7c40734..b82c59c3 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 6e0609c3..a2674ab3 100644 --- a/src/libcamera/event_dispatcher_poll.cpp +++ b/src/libcamera/event_dispatcher_poll.cpp @@ -8,7 +8,10 @@ #include <algorithm> #include <iomanip> #include <poll.h> +#include <stdint.h> #include <string.h> +#include <sys/eventfd.h> +#include <unistd.h> #include <libcamera/event_notifier.h> #include <libcamera/timer.h> @@ -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<struct pollfd> 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<struct pollfd> *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<struct pollfd> &pollfds) { static const struct { diff --git a/src/libcamera/include/event_dispatcher_poll.h b/src/libcamera/include/event_dispatcher_poll.h index ac3efde0..1c0066c2 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<int, EventNotifierSetPoll> notifiers_; std::list<Timer *> timers_; + int eventfd_; int poll(std::vector<struct pollfd> *pollfds); + void processInterrupt(const struct pollfd &pfd); void processNotifiers(const std::vector<struct pollfd> &pollfds); void processTimers(); }; |