-
Notifications
You must be signed in to change notification settings - Fork 49
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
[ffigen] Blocking blocks #1796
Open
liamappelbe
wants to merge
11
commits into
main
Choose a base branch
from
blockblock
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
[ffigen] Blocking blocks #1796
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Add a new
.blocking()
constructor to all ObjC blocks that returnvoid
. This constructor returns a block that can be invoked from any thread, and blocks the caller until the Dart callback is complete.Under the hood it has two modes, depending on whether it's invoked from the same thread as the isolate that created the block, or a different thread. If it's on the same thread, it uses a
NativeCallable.isolateLocal
, and doesn't need anything special to get blocking behavior. If it's on a different thread, it uses aNativeCallable.listener
, and uses an ObjC condition variable,NSCondition
, to wait for the callback to complete. This difference avoids deadlocks in the on-thread case.Async callbacks aren't supported in either case. It would be trivial to support them in the off-thread case, but difficult/impossible in the on-thread case. So to avoid semantic differences I'm just not supporting them at all.
There are still edge cases where it's possible to deadlock. If the target isolate has shut down, and the block is invoked from a different thread, then it will send a message to a non-existent isolate and wait forever to be signaled. To mitigate this case we use a timeout when waiting on the condition variable. That timeout can be set by the user.
The different behavior on-thread vs off-thread means we need two Dart-side trampolines, and two blocks passed to the native block wrapper. You can see how it all works by looking at the new ObjC-side trampolines. For example:
Part of #1647. Non-void callbacks and blocking protocol methods are left as follow up work.
Details
newWaiter
,signalWaiter
, andawaitWaiter
.DOBJCWaiter
, which just wraps anNSCondition
and abool
flag. The flag is needed because whenever you wait on a condition variable, there can be spurious wake ups.newWaiter
returns an object with a +2 ref count, and the other two each decrement the ref count by 1.newWaiter
andawaitWaiter
functions from package:objective_c. So instead I'm passing them down as function pointers. That's what package:objective_c's newwrapBlockingBlock
function is for.