[libcamera-devel] [PATCH 3/4] libcamera: event_dispatcher: Add interrupt() function

Laurent Pinchart laurent.pinchart at ideasonboard.com
Wed Jan 23 09:59:22 CET 2019


The new interrupt() function allows interrupting in-progress blocking
processEvents() calls. This is useful to stop running event loops.

Signed-off-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
---
 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 <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 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<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();
 };
-- 
Regards,

Laurent Pinchart



More information about the libcamera-devel mailing list