summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2019-07-12 13:38:50 +0300
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2019-07-13 07:47:36 +0300
commit3e14a1bcb0557e73718d12cd7ef113940472a934 (patch)
tree48429ccb4581e6173b6ddb372cc2545523606bb1
parent8f1dbd6a92381e38ba4bf65bdc35d5475ae6dc0a (diff)
libcamera: event_notifier_poll: Fix notifier unregistration during event processing
An event notifier may be unregistered from its activated signal. This can cause the notifiers set entry in notifiers_ to be deleted while processNotifiers() is looping over the notifiers_ map, leading to problems. To fix this, add a flag to the EventNotifierPoll class to indicate that event processing is in progress. If the flag is set, the notifiers_ entry is not deleted during notifier unregistration, but will be deleted by the event processing loop. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Paul Elder <paul.elder@ideasonboard.com> Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
-rw-r--r--src/libcamera/event_dispatcher_poll.cpp18
-rw-r--r--src/libcamera/include/event_dispatcher_poll.h2
2 files changed, 20 insertions, 0 deletions
diff --git a/src/libcamera/event_dispatcher_poll.cpp b/src/libcamera/event_dispatcher_poll.cpp
index df9dffb2..4f15f3e3 100644
--- a/src/libcamera/event_dispatcher_poll.cpp
+++ b/src/libcamera/event_dispatcher_poll.cpp
@@ -46,6 +46,7 @@ static const char *notifierType(EventNotifier::Type type)
*/
EventDispatcherPoll::EventDispatcherPoll()
+ : processingEvents_(false)
{
/*
* Create the event fd. Failures are fatal as we can't implement an
@@ -96,6 +97,15 @@ void EventDispatcherPoll::unregisterEventNotifier(EventNotifier *notifier)
}
set.notifiers[type] = nullptr;
+
+ /*
+ * Don't race with event processing if this method is called from an
+ * event notifier. The notifiers_ entry will be erased by
+ * processEvents().
+ */
+ if (processingEvents_)
+ return;
+
if (!set.notifiers[0] && !set.notifiers[1] && !set.notifiers[2])
notifiers_.erase(iter);
}
@@ -241,6 +251,8 @@ void EventDispatcherPoll::processNotifiers(const std::vector<struct pollfd> &pol
{ EventNotifier::Exception, POLLPRI },
};
+ processingEvents_ = true;
+
for (const pollfd &pfd : pollfds) {
auto iter = notifiers_.find(pfd.fd);
ASSERT(iter != notifiers_.end());
@@ -269,7 +281,13 @@ void EventDispatcherPoll::processNotifiers(const std::vector<struct pollfd> &pol
if (pfd.revents & event.events)
notifier->activated.emit(notifier);
}
+
+ /* Erase the notifiers_ entry if it is now empty. */
+ if (!set.notifiers[0] && !set.notifiers[1] && !set.notifiers[2])
+ notifiers_.erase(iter);
}
+
+ processingEvents_ = false;
}
void EventDispatcherPoll::processTimers()
diff --git a/src/libcamera/include/event_dispatcher_poll.h b/src/libcamera/include/event_dispatcher_poll.h
index 14c3eea1..d82b302c 100644
--- a/src/libcamera/include/event_dispatcher_poll.h
+++ b/src/libcamera/include/event_dispatcher_poll.h
@@ -45,6 +45,8 @@ private:
std::list<Timer *> timers_;
int eventfd_;
+ bool processingEvents_;
+
int poll(std::vector<struct pollfd> *pollfds);
void processInterrupt(const struct pollfd &pfd);
void processNotifiers(const std::vector<struct pollfd> &pollfds);