summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiklas Söderlund <niklas.soderlund@ragnatech.se>2021-01-30 00:52:54 +0100
committerNiklas Söderlund <niklas.soderlund@ragnatech.se>2021-02-05 11:10:29 +0100
commit5b60b689c14bcb84ee034bdf400a75c0b63ef999 (patch)
treea9782ee8b17607479f4bfacd8271a230a444c634
parent297c9c3fa081a98f4f8657fe19ef33e6cec10bd0 (diff)
cam: event_loop: Execute events in the libevent loop
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 by removing the custom event execution and instead injecting the calls as events to the base event loop. Reported-by: Sebastian Fricke <sebastian.fricke@posteo.net> Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-rw-r--r--src/cam/event_loop.cpp40
-rw-r--r--src/cam/event_loop.h9
2 files changed, 23 insertions, 26 deletions
diff --git a/src/cam/event_loop.cpp b/src/cam/event_loop.cpp
index 3a2b665a..6a4c47f2 100644
--- a/src/cam/event_loop.cpp
+++ b/src/cam/event_loop.cpp
@@ -38,25 +38,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 +55,28 @@ void EventLoop::callLater(const std::function<void()> &func)
calls_.push_back(func);
}
- interrupt();
+ event_base_once(base_, -1, EV_TIMEOUT, dispatchCallback, this, nullptr);
}
-void EventLoop::dispatchCalls()
+void EventLoop::dispatchCallback([[maybe_unused]] evutil_socket_t fd,
+ [[maybe_unused]] short flags, void *param)
{
- std::unique_lock<std::mutex> locker(lock_);
+ EventLoop *loop = static_cast<EventLoop *>(param);
+ loop->dispatchCall();
+}
- for (auto iter = calls_.begin(); iter != calls_.end(); ) {
- std::function<void()> call = std::move(*iter);
+void EventLoop::dispatchCall()
+{
+ std::function<void()> call;
- iter = calls_.erase(iter);
+ {
+ std::unique_lock<std::mutex> locker(lock_);
+ if (calls_.empty())
+ return;
- 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 d0d5b5a5..ba3ba3a4 100644
--- a/src/cam/event_loop.h
+++ b/src/cam/event_loop.h
@@ -7,11 +7,12 @@
#ifndef __CAM_EVENT_LOOP_H__
#define __CAM_EVENT_LOOP_H__
-#include <atomic>
#include <functional>
#include <list>
#include <mutex>
+#include <event2/util.h>
+
struct event_base;
class EventLoop
@@ -31,14 +32,14 @@ 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();
+ static void dispatchCallback(evutil_socket_t fd, short flags,
+ void *param);
+ void dispatchCall();
};
#endif /* __CAM_EVENT_LOOP_H__ */