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

Jacopo Mondi jacopo at jmondi.org
Wed Feb 3 12:35:24 CET 2021


On Tue, Feb 02, 2021 at 11:10:50PM +0100, Niklas Söderlund wrote:
> 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

s/my/by

> 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_;

Is this returning -1 unconditionally ? Is this intended ?

>  }
>
>  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()

This now doesn't dispatch but rather run the first callback.
execCallback() ? execOne() ? runCallback() ?

>  {
> -	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();

Change looks ok!
Reviewed-by: Jacopo Mondi <jacopo at jmondi.org>

Thanks
  j

>  };
>
>  #endif /* __CAM_EVENT_LOOP_H__ */
> --
> 2.30.0
>
> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel at lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel


More information about the libcamera-devel mailing list