From f34a2899e464b31d301c706b16966bfa3236a4a7 Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Fri, 23 Apr 2021 15:57:58 -0700 Subject: [PATCH] Invalidate TurboModules on their method queues Summary: ## Rationale With the bridge, the invalidate method of every TurboModule gets called on the TurboModule's method queue. This ensures that we can safely clean up resources accessed in the TurboModule's async methods. In bridgeless mode, we don't invalidate each module on its method queue. After this diff, we will clean up every TurboModule on its own method queue. ## Changes - Make RCTInstance dealloc itself on the JavaScript thread. - Terminate the JavaScript thread on the JavaScript thread. This ensures that no work executes on the JavaScript thread after we clean up RCTInstance. - Make [RCTTurboModuleManager invalidate] execute right before RCTInstance terminates the JavaScript thread. - **Fix:** Make [RCTTurboModuleManger invalidate] synchronously invalidate modules on their own method queues. Changelog: [Internal] Reviewed By: PeteTheHeat Differential Revision: D27933587 fbshipit-source-id: 7630e7fc074df2f5a3293192431105c747b8588f --- .../platform/ios/RCTTurboModuleManager.mm | 73 ++++++++++--------- 1 file changed, 39 insertions(+), 34 deletions(-) diff --git a/ReactCommon/react/nativemodule/core/platform/ios/RCTTurboModuleManager.mm b/ReactCommon/react/nativemodule/core/platform/ios/RCTTurboModuleManager.mm index 8d755a6961b..b43a4512b31 100644 --- a/ReactCommon/react/nativemodule/core/platform/ios/RCTTurboModuleManager.mm +++ b/ReactCommon/react/nativemodule/core/platform/ios/RCTTurboModuleManager.mm @@ -834,6 +834,27 @@ static Class getFallbackClassFromName(const char *name) return; } + [self _enterInvalidatingState]; +} + +- (void)bridgeDidInvalidateModules:(NSNotification *)notification +{ + RCTBridge *bridge = notification.userInfo[@"bridge"]; + if (bridge != _bridge) { + return; + } + + [self _invalidateModules]; +} + +- (void)invalidate +{ + [self _enterInvalidatingState]; + [self _invalidateModules]; +} + +- (void)_enterInvalidatingState +{ // This should halt all insertions into _turboModuleHolders if (RCTTurboModuleSharedMutexInitEnabled()) { std::unique_lock guard(_turboModuleHoldersSharedMutex); @@ -844,13 +865,8 @@ static Class getFallbackClassFromName(const char *name) } } -- (void)bridgeDidInvalidateModules:(NSNotification *)notification +- (void)_invalidateModules { - RCTBridge *bridge = notification.userInfo[@"bridge"]; - if (bridge != _bridge) { - return; - } - // Backward-compatibility: RCTInvalidating handling. dispatch_group_t moduleInvalidationGroup = dispatch_group_create(); @@ -870,17 +886,28 @@ static Class getFallbackClassFromName(const char *name) if ([module respondsToSelector:@selector(invalidate)]) { if ([module respondsToSelector:@selector(methodQueue)]) { dispatch_queue_t methodQueue = [module performSelector:@selector(methodQueue)]; + if (methodQueue) { dispatch_group_enter(moduleInvalidationGroup); - [bridge - dispatchBlock:^{ - [((id)module) invalidate]; - dispatch_group_leave(moduleInvalidationGroup); - } - queue:methodQueue]; + dispatch_block_t invalidateModule = ^{ + [((id)module) invalidate]; + dispatch_group_leave(moduleInvalidationGroup); + }; + + if (_bridge) { + [_bridge dispatchBlock:invalidateModule queue:methodQueue]; + } else { + // Bridgeless mode + if (methodQueue == RCTJSThread) { + invalidateModule(); + } else { + dispatch_async(methodQueue, invalidateModule); + } + } continue; } } + [((id)module) invalidate]; } } @@ -893,26 +920,4 @@ static Class getFallbackClassFromName(const char *name) _turboModuleCache.clear(); } -- (void)invalidate -{ - if (RCTTurboModuleSharedMutexInitEnabled()) { - std::unique_lock guard(_turboModuleHoldersSharedMutex); - _invalidating = true; - } else { - std::lock_guard guard(_turboModuleHoldersMutex); - _invalidating = true; - } - - // Backward-compatibility: RCTInvalidating handling, but not adhering to desired methodQueue. - for (const auto &p : _turboModuleHolders) { - id module = p.second.getModule(); - if ([module respondsToSelector:@selector(invalidate)]) { - [((id)module) invalidate]; - } - } - - _turboModuleHolders.clear(); - _turboModuleCache.clear(); -} - @end