From 68fd1e55085e871a854563721ee29ca698239607 Mon Sep 17 00:00:00 2001 From: Imran Shitta-Bey Date: Tue, 29 Mar 2022 14:04:07 -0700 Subject: [PATCH] fix: deadlock when sending events (#33490) Summary: In short, if an RCTEventDispatcher observer sends an event on the same thread that the observer was initially on, there will be a deadlock due to `sendEvent` already having the lock active on the `_observers` NSHashTable. An example where this occurred was when we had react-native-gesture-handler trigger an animated event, which then triggered an event on the underlying component being animated as a result of it being an observer on the animation event. Since this all occurred on the main thread, we ended up with a deadlock and the app froze. To prevent this scenario, I used a `NSRecursiveLock` for _observersLock to be able to dispatch events on the same thread from observers. joebernard ## Changelog [iOS] [Fix] - Prevent deadlock when dispatching events from observers on the same thread. Pull Request resolved: https://github.com/facebook/react-native/pull/33490 Test Plan: Not sure if there are any tests present for sending events with RCTEventDispatcher already in place, but In regular app usage this solution has proved to be a viable and stable option so far and has prevented the deadlock from occurring. This would still be thread-safe since we are now allowing the event to be sent through observers on the same thread the initial event was dispatched on. The only issue I could see here is the behavior of sending an event could be changed. Reviewed By: RSNara Differential Revision: D35118752 Pulled By: charlesbdudley fbshipit-source-id: 7e93a8d49841e001b235a437ccca1e072dcc7ab1 --- React/CoreModules/RCTEventDispatcher.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/React/CoreModules/RCTEventDispatcher.mm b/React/CoreModules/RCTEventDispatcher.mm index ab63111c874..ef6a895f12b 100644 --- a/React/CoreModules/RCTEventDispatcher.mm +++ b/React/CoreModules/RCTEventDispatcher.mm @@ -37,7 +37,7 @@ static uint16_t RCTUniqueCoalescingKeyGenerator = 0; NSMutableArray *_eventQueue; BOOL _eventsDispatchScheduled; NSHashTable> *_observers; - NSLock *_observersLock; + NSRecursiveLock *_observersLock; } @synthesize bridge = _bridge; @@ -53,7 +53,7 @@ RCT_EXPORT_MODULE() _eventQueueLock = [NSLock new]; _eventsDispatchScheduled = NO; _observers = [NSHashTable weakObjectsHashTable]; - _observersLock = [NSLock new]; + _observersLock = [NSRecursiveLock new]; } - (void)sendViewEventWithName:(NSString *)name reactTag:(NSNumber *)reactTag