diff options
author | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2019-07-12 13:38:50 +0300 |
---|---|---|
committer | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2019-07-13 07:47:36 +0300 |
commit | 3e14a1bcb0557e73718d12cd7ef113940472a934 (patch) | |
tree | 48429ccb4581e6173b6ddb372cc2545523606bb1 | |
parent | 8f1dbd6a92381e38ba4bf65bdc35d5475ae6dc0a (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.cpp | 18 | ||||
-rw-r--r-- | src/libcamera/include/event_dispatcher_poll.h | 2 |
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); |