-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Resolve sync UI updates concurency issue on iOS #4403
Conversation
RCTAssert(_mounting == nil, @"Mouting block was set but never executed. This may lead to UI inconsistencies"); | ||
} | ||
|
||
- (void)unblockUIThread |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The name "unblockUIThread" is quite ambiguous in this context
- (void)unblockUIThread | |
- (void)unblockUIManagerThread |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But we unblock UI thread here because it is waiting on the semaphore that we signal. The UIManager thread is not blocked at this point and it is the thread where this method can be run from
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah yes, my bad, I was confused by RCTAssertUIManagerQueue()
but it makes sense now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me, just wondering if we should to move the code to REASyncUpdateObserver.h
and REASyncUpdateObserver.mm
but this class is only used from REANodesManager.mm
so that's okay.
This should perhaps be backported to 2.x branch, similarly to how we did with #4239 which introduced this problem |
Sorry if I misunderstand this pr but shouldn't this solve #2285 ? |
Hey, to what version have you merged this pr? |
@raphaelinmanage this pr is for v3 |
Hey, the issue is exists on v2.17.0 as well. Do you plan to fix it on v2? @LeviWilliams @kmagiera |
@kaancembertas there is a comment right above stating that they intend to do this though I wouldn't hold your breath on backwards compat maintenance. I would recommend migrating to v3 anyways as quickly as possible, there are large gains in stability and performance in v3. |
Still experiencing this in 3.1.0 when switching between bottom sheets using react-native-bottom-sheet |
It's not released yet I think. I just applied the patch manually and it also fixes one of my issues I had. 👍 |
## Summary This PR tries to address the problem with assert that we make in `REANodesManager.mm` when receiving mounting block from the React's UI Manager. The issue was due to a fact that we only hold a single reference for mounting block as well as the timed-out flag, while under certain conditions, the `performOperations` may re-enter before these values are cleaned up correctly. This didn't happen before software-mansion#4239 because the lock would guarantee that `performIOperation` is never called again before the block scheduled on UIManagerQueue is finished. However in software-mansion#4239 we changed this behavior to stop potential ANR issues due to locking and this caused this new issue to surface. The change we are making here is that we create a new instance of observer that is specific to a given `performOperation` call. This way every call to `performOperation` shares an instance of observer with UIManagerQueue bloc, which keeps ref to mounting block and timeout flag, hence it is never possible for read/writes of these refs to interfere between subsequent `performOperation` runs. We are now also moving the assert to the new place – to the observer dealloc. We always expect the mounting block to be executed (and cleaned up) and hence if the observer is deallocated with the mounting block set, we treat this as an error. ## Test plan We couldn't manage to reproduce this issue but it was tested courtesy of @gavrix who could reliably reproduce the assert failure on one of the apps he works on.
I have backported the fix to v2 while also fixing a typescript issue, using a patch:
I was hoping they would bring it to v2 but it looks like they've already abandoned it. Migrating to v3 isn't an option on the project I'm working on currently unfortunately, hence the patch. |
Summary
This PR tries to address the problem with assert that we make in
REANodesManager.mm
when receiving mounting block from the React's UI Manager.The issue was due to a fact that we only hold a single reference for mounting block as well as the timed-out flag, while under certain conditions, the
performOperations
may re-enter before these values are cleaned up correctly. This didn't happen before #4239 because the lock would guarantee thatperformIOperation
is never called again before the block scheduled on UIManagerQueue is finished. However in #4239 we changed this behavior to stop potential ANR issues due to locking and this caused this new issue to surface.The change we are making here is that we create a new instance of observer that is specific to a given
performOperation
call. This way every call toperformOperation
shares an instance of observer with UIManagerQueue bloc, which keeps ref to mounting block and timeout flag, hence it is never possible for read/writes of these refs to interfere between subsequentperformOperation
runs.We are now also moving the assert to the new place – to the observer dealloc. We always expect the mounting block to be executed (and cleaned up) and hence if the observer is deallocated with the mounting block set, we treat this as an error.
Test plan
We couldn't manage to reproduce this issue but it was tested courtesy of @gavrix who could reliably reproduce the assert failure on one of the apps he works on.