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
This commit is contained in:
Ramanpreet Nara authored and Facebook GitHub Bot committed 2021-04-23 15:59:24 -07:00
1 parent 090196f330
commit f34a2899e4
1 file changed
+39 -34
@@ -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<std::shared_timed_mutex> 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<RCTInvalidating>)module) invalidate];
dispatch_group_leave(moduleInvalidationGroup);
}
queue:methodQueue];
dispatch_block_t invalidateModule = ^{
[((id<RCTInvalidating>)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<RCTInvalidating>)module) invalidate];
}
}
@@ -893,26 +920,4 @@ static Class getFallbackClassFromName(const char *name)
_turboModuleCache.clear();
}
- (void)invalidate
{
if (RCTTurboModuleSharedMutexInitEnabled()) {
std::unique_lock<std::shared_timed_mutex> guard(_turboModuleHoldersSharedMutex);
_invalidating = true;
} else {
std::lock_guard<std::mutex> guard(_turboModuleHoldersMutex);
_invalidating = true;
}
// Backward-compatibility: RCTInvalidating handling, but not adhering to desired methodQueue.
for (const auto &p : _turboModuleHolders) {
id<RCTTurboModule> module = p.second.getModule();
if ([module respondsToSelector:@selector(invalidate)]) {
[((id<RCTInvalidating>)module) invalidate];
}
}
_turboModuleHolders.clear();
_turboModuleCache.clear();
}
@end