[RFC,v3,06/21] apps: common: event_loop: Add way to cancel deferred calls
diff mbox series

Message ID 20250130115001.1129305-7-pobrn@protonmail.com
State New
Headers show
Series
  • apps: lc-compliance: Multi-stream tests
Related show

Commit Message

Barnabás Pőcze Jan. 30, 2025, 11:50 a.m. UTC
Store a cookie value of `std::uintptr_t` with the callback to
make later cancellation of the callback possible.

Signed-off-by: Barnabás Pőcze <pobrn@protonmail.com>
---
 src/apps/common/event_loop.cpp | 18 ++++++++++++++----
 src/apps/common/event_loop.h   |  6 ++++--
 2 files changed, 18 insertions(+), 6 deletions(-)

Comments

Jacopo Mondi Feb. 4, 2025, 10 a.m. UTC | #1
Hi Barnabás

On Thu, Jan 30, 2025 at 11:50:32AM +0000, Barnabás Pőcze wrote:
> Store a cookie value of `std::uintptr_t` with the callback to
> make later cancellation of the callback possible.
>
> Signed-off-by: Barnabás Pőcze <pobrn@protonmail.com>
> ---
>  src/apps/common/event_loop.cpp | 18 ++++++++++++++----
>  src/apps/common/event_loop.h   |  6 ++++--
>  2 files changed, 18 insertions(+), 6 deletions(-)
>
> diff --git a/src/apps/common/event_loop.cpp b/src/apps/common/event_loop.cpp
> index b6230f4ba..0d7a4a024 100644
> --- a/src/apps/common/event_loop.cpp
> +++ b/src/apps/common/event_loop.cpp
> @@ -10,6 +10,7 @@
>  #include <assert.h>
>  #include <event2/event.h>
>  #include <event2/thread.h>
> +#include <algorithm>
>  #include <iostream>
>
>  EventLoop *EventLoop::instance_ = nullptr;
> @@ -33,7 +34,7 @@ EventLoop::EventLoop()
>  				if (self->calls_.empty())
>  					break;
>
> -				call = std::move(self->calls_.front());
> +				call = std::move(self->calls_.front().first);
>  				self->calls_.pop_front();
>  			}
>
> @@ -73,16 +74,25 @@ void EventLoop::exit(int code)
>  	event_base_loopbreak(base_);
>  }
>
> -void EventLoop::callLater(std::function<void()> &&func)
> +void EventLoop::callLater(std::function<void()> &&func, std::optional<std::uintptr_t> cookie)

Is this a good idea to make cookie optional ?
As far as I can see !cookie means all pending callbacks are deleted

>  {
>  	{
> -		std::unique_lock<std::mutex> locker(lock_);
> -		calls_.push_back(std::move(func));
> +		std::lock_guard locker(lock_);
> +		calls_.emplace_back(std::move(func), cookie);
>  	}
>
>  	event_active(callsTrigger_, 0, 0);
>  }
>
> +void EventLoop::cancelLater(std::optional<std::uintptr_t> cookie)
> +{
> +	std::lock_guard locker(lock_);
> +
> +	calls_.erase(std::remove_if(calls_.begin(), calls_.end(),
> +				    [&](const auto &x) { return !cookie || x.second == *cookie; }),

Can x.second be invalid ?

I guess so looking at the call of

src/apps/cam/camera_session.cpp:
EventLoop::instance()->callLater([this, request]() { processRequest(request); });

Making the cookie (which is a reference to the caller, that's it)
mandatory would make the code simpler ?

Also why do you need to dereference cookie here ? Can't you just
compare the two optional<> ?

Thanks
  j


> +		     calls_.end());
> +}
> +
>  void EventLoop::addFdEvent(int fd, EventType type,
>  			   std::function<void()> &&callback)
>  {
> diff --git a/src/apps/common/event_loop.h b/src/apps/common/event_loop.h
> index 507023996..6d7d0497a 100644
> --- a/src/apps/common/event_loop.h
> +++ b/src/apps/common/event_loop.h
> @@ -13,6 +13,7 @@
>  #include <list>
>  #include <memory>
>  #include <mutex>
> +#include <optional>
>
>  #include <libcamera/base/class.h>
>
> @@ -36,7 +37,8 @@ public:
>  	int exec();
>  	void exit(int code = 0);
>
> -	void callLater(std::function<void()> &&func);
> +	void callLater(std::function<void()> &&func, std::optional<std::uintptr_t> cookie = {});
> +	void cancelLater(std::optional<std::uintptr_t> cookie = {});
>
>  	void addFdEvent(int fd, EventType type,
>  			std::function<void()> &&handler);
> @@ -63,7 +65,7 @@ private:
>  	struct event_base *base_;
>  	int exitCode_;
>
> -	std::deque<std::function<void()>> calls_;
> +	std::deque<std::pair<std::function<void()>, std::optional<std::uintptr_t>>> calls_;
>  	::event *callsTrigger_ = nullptr;
>
>  	std::list<std::unique_ptr<Event>> events_;
> --
> 2.48.1
>
>

Patch
diff mbox series

diff --git a/src/apps/common/event_loop.cpp b/src/apps/common/event_loop.cpp
index b6230f4ba..0d7a4a024 100644
--- a/src/apps/common/event_loop.cpp
+++ b/src/apps/common/event_loop.cpp
@@ -10,6 +10,7 @@ 
 #include <assert.h>
 #include <event2/event.h>
 #include <event2/thread.h>
+#include <algorithm>
 #include <iostream>
 
 EventLoop *EventLoop::instance_ = nullptr;
@@ -33,7 +34,7 @@  EventLoop::EventLoop()
 				if (self->calls_.empty())
 					break;
 
-				call = std::move(self->calls_.front());
+				call = std::move(self->calls_.front().first);
 				self->calls_.pop_front();
 			}
 
@@ -73,16 +74,25 @@  void EventLoop::exit(int code)
 	event_base_loopbreak(base_);
 }
 
-void EventLoop::callLater(std::function<void()> &&func)
+void EventLoop::callLater(std::function<void()> &&func, std::optional<std::uintptr_t> cookie)
 {
 	{
-		std::unique_lock<std::mutex> locker(lock_);
-		calls_.push_back(std::move(func));
+		std::lock_guard locker(lock_);
+		calls_.emplace_back(std::move(func), cookie);
 	}
 
 	event_active(callsTrigger_, 0, 0);
 }
 
+void EventLoop::cancelLater(std::optional<std::uintptr_t> cookie)
+{
+	std::lock_guard locker(lock_);
+
+	calls_.erase(std::remove_if(calls_.begin(), calls_.end(),
+				    [&](const auto &x) { return !cookie || x.second == *cookie; }),
+		     calls_.end());
+}
+
 void EventLoop::addFdEvent(int fd, EventType type,
 			   std::function<void()> &&callback)
 {
diff --git a/src/apps/common/event_loop.h b/src/apps/common/event_loop.h
index 507023996..6d7d0497a 100644
--- a/src/apps/common/event_loop.h
+++ b/src/apps/common/event_loop.h
@@ -13,6 +13,7 @@ 
 #include <list>
 #include <memory>
 #include <mutex>
+#include <optional>
 
 #include <libcamera/base/class.h>
 
@@ -36,7 +37,8 @@  public:
 	int exec();
 	void exit(int code = 0);
 
-	void callLater(std::function<void()> &&func);
+	void callLater(std::function<void()> &&func, std::optional<std::uintptr_t> cookie = {});
+	void cancelLater(std::optional<std::uintptr_t> cookie = {});
 
 	void addFdEvent(int fd, EventType type,
 			std::function<void()> &&handler);
@@ -63,7 +65,7 @@  private:
 	struct event_base *base_;
 	int exitCode_;
 
-	std::deque<std::function<void()>> calls_;
+	std::deque<std::pair<std::function<void()>, std::optional<std::uintptr_t>>> calls_;
 	::event *callsTrigger_ = nullptr;
 
 	std::list<std::unique_ptr<Event>> events_;