[libcamera-devel] [PATCH v4 2/3] cam: event_loop: Execute events in the libevent loop

Niklas Söderlund niklas.soderlund at ragnatech.se
Tue Feb 2 23:10:50 CET 2021


Cam uses libevent to deal with threads and idle loop while still
implementing its own event queue. This creates issues when the event
loop is terminated as it might get stuck in the idle loop if exit() is
called while the thread is busy with dispatchCalls().

Solve this my removing the custom event execution and instead injecting
the calls as events to the base event loop.

Reported-by: Sebastian Fricke <sebastian.fricke at posteo.net>
Signed-off-by: Niklas Söderlund <niklas.soderlund at ragnatech.se>
---
 src/cam/event_loop.cpp | 43 ++++++++++++++++++++----------------------
 src/cam/event_loop.h   |  6 +-----
 2 files changed, 21 insertions(+), 28 deletions(-)

diff --git a/src/cam/event_loop.cpp b/src/cam/event_loop.cpp
index 3a2b665abdc063de..e84e437f1f8ff6d7 100644
--- a/src/cam/event_loop.cpp
+++ b/src/cam/event_loop.cpp
@@ -13,6 +13,13 @@
 
 EventLoop *EventLoop::instance_ = nullptr;
 
+static void dispatchCallback([[maybe_unused]] evutil_socket_t fd,
+			     [[maybe_unused]] short flags, void *param)
+{
+	EventLoop *loop = static_cast<EventLoop *>(param);
+	loop->dispatchCall();
+}
+
 EventLoop::EventLoop()
 {
 	assert(!instance_);
@@ -38,25 +45,13 @@ EventLoop *EventLoop::instance()
 int EventLoop::exec()
 {
 	exitCode_ = -1;
-	exit_.store(false, std::memory_order_release);
-
-	while (!exit_.load(std::memory_order_acquire)) {
-		dispatchCalls();
-		event_base_loop(base_, EVLOOP_NO_EXIT_ON_EMPTY);
-	}
-
+	event_base_loop(base_, EVLOOP_NO_EXIT_ON_EMPTY);
 	return exitCode_;
 }
 
 void EventLoop::exit(int code)
 {
 	exitCode_ = code;
-	exit_.store(true, std::memory_order_release);
-	interrupt();
-}
-
-void EventLoop::interrupt()
-{
 	event_base_loopbreak(base_);
 }
 
@@ -67,20 +62,22 @@ void EventLoop::callLater(const std::function<void()> &func)
 		calls_.push_back(func);
 	}
 
-	interrupt();
+	struct event *event = event_new(base_, -1, 0, dispatchCallback, this);
+	event_active(event, 0, 0);
 }
 
-void EventLoop::dispatchCalls()
+void EventLoop::dispatchCall()
 {
-	std::unique_lock<std::mutex> locker(lock_);
+	std::function<void()> call;
 
-	for (auto iter = calls_.begin(); iter != calls_.end(); ) {
-		std::function<void()> call = std::move(*iter);
+	{
+		std::unique_lock<std::mutex> locker(lock_);
+		if (calls_.empty())
+			return;
 
-		iter = calls_.erase(iter);
-
-		locker.unlock();
-		call();
-		locker.lock();
+		call = calls_.front();
+		calls_.pop_front();
 	}
+
+	call();
 }
diff --git a/src/cam/event_loop.h b/src/cam/event_loop.h
index d0d5b5a53c830670..5f1cd88c2f5c830e 100644
--- a/src/cam/event_loop.h
+++ b/src/cam/event_loop.h
@@ -7,7 +7,6 @@
 #ifndef __CAM_EVENT_LOOP_H__
 #define __CAM_EVENT_LOOP_H__
 
-#include <atomic>
 #include <functional>
 #include <list>
 #include <mutex>
@@ -26,19 +25,16 @@ public:
 	void exit(int code = 0);
 
 	void callLater(const std::function<void()> &func);
+	void dispatchCall();
 
 private:
 	static EventLoop *instance_;
 
 	struct event_base *base_;
-	std::atomic<bool> exit_;
 	int exitCode_;
 
 	std::list<std::function<void()>> calls_;
 	std::mutex lock_;
-
-	void interrupt();
-	void dispatchCalls();
 };
 
 #endif /* __CAM_EVENT_LOOP_H__ */
-- 
2.30.0



More information about the libcamera-devel mailing list