Skip to content

Commit 859dbee

Browse files
authored
SE-0424: assign to the checkIsolated proposal and put into review
1 parent 1f69fe4 commit 859dbee

File tree

1 file changed

+10
-24
lines changed

1 file changed

+10
-24
lines changed

proposals/NNNN-custom-isolation-checking-for-serialexecutor.md renamed to proposals/0424-custom-isolation-checking-for-serialexecutor.md

Lines changed: 10 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
# Custom isolation checking for SerialExecutor
22

3-
* Proposal: [SE-NNNN](NNNN-advanced-custom-isolation-checking-for-serialexecutor.md)
3+
* Proposal: [SE-0424](0424-advanced-custom-isolation-checking-for-serialexecutor.md)
44
* Author: [Konrad 'ktoso' Malawski](https://github.com/ktoso)
5-
* Review Manager: ???
6-
* Status: **Work in Progress**
5+
* Review Manager: [John McCall](https://github.com/rjmccall)
6+
* Status: **Active Review (Feburary 22nd...March 4th, 2024)**
77
* Implementation: [PR #71172](https://github.com/apple/swift/pull/71172)
8-
* Review: ???
8+
* Review: ([pitch](https://forums.swift.org/t/pitch-custom-isolation-checking-for-serialexecutor/69786))
99

1010
## Introduction
1111

@@ -15,7 +15,6 @@
1515

1616
The Swift concurrency runtime dynamically tracks the current executor of a running task in thread-local storage. To run code on behalf of a task, an executor must call into the runtime, and the runtime will set up the tracking appropriately. APIs like `assertIsolated` and `assumeIsolated` are built on top of that functionality and perform their checks by comparing the expected executor with the current executor tracked by the runtime. If the current thread is not running a task, the runtime treats it as if it were running a non-isolated function, and the comparison will fail.
1717

18-
1918
This logic is not sufficient to handle the situation in which code is running on an actor's serial executor, but the code is not associated with a task. Swift's default actor executors currently do not provide any way to enqueue work on them that is not associated with a task, so this situation does not apply to them. However, many custom executors do provide other APIs for enqueuing work, such as the `async` method on `DispatchSerialQueue`. These APIs are not required to inform the Swift concurrency runtime before running the code. As a result, the runtime will be unaware that the current thread is associated with an actor's executor, and checks like `assumeIsolated` will fail. This is undesirable because, as long as the executor still acts like a serial executor for any non-task code it runs this way, the code will still be effectively actor-isolated: no code that accesses the actor's isolated state can run concurrently with it.
2019

2120
The following example demonstrates such a situation:
@@ -46,7 +45,7 @@ actor Caplin {
4645
}
4746
```
4847

49-
Even though the code is executing on the correct Dispatch**Serial**Queue, the assertions trigger and we're left unable to access the actor's state, even though isolation wise it would be safe and correct to do so.
48+
Even though the code is executing on the correct Dispatch**Serial**Queue, the assertions trigger and we're left unable to access the actor's state, even though isolation-wise it would be safe and correct to do so.
5049

5150
Being able to assert isolation for non-task code this way is important enough that the Swift runtime actually already has a special case for it: even if the current thread is not running a task, isolation checking will succeed if the target actor is the `MainActor` and the current thread is the *main thread*. This problem is more general than the main actor, however; it exists for all kinds of threads which may be used as actor executors. The most important example of this is `DispatchSerialQueue`, especially because it is so commonly used in pre-concurrency code bases to provide actor-like isolation. Allowing types like `DispatchSerialQueue` to hook into isolation checking makes it much easier to gradually migrate code to actors: if an actor uses a queue as its executor, existing code that uses the queue don't have to be completely rewritten in order to access the actor's state.
5251

@@ -87,7 +86,7 @@ extension SerialExecutor {
8786

8887
## Detailed design
8988

90-
This proposal adds another customization point to the Swift concurrency runtime that hooks into isolation context comparison mechanisms used by `assertIsolated`, `preconditionIsolated`, `assumeIsolated` as well as implicitly injected assertions used in `@preconcurrency` code.
89+
This proposal adds another customization point to the Swift concurrency runtime that hooks into isolation context comparison mechanisms used by `assertIsolated`, `preconditionIsolated`, and `assumeIsolated`, as well as any implicitly injected assertions used in `@preconcurrency` code.
9190

9291
### Extended executor comparison mechanism
9392

@@ -125,8 +124,8 @@ if isSameSerialExecutor(current, expected) {
125124
return // ok, it seems the expected executor was able to prove isolation
126125
```
127126

128-
This pseudo code snippet explains the flow of the executor comparisons. There are two situations in which the new `checkIsolated` method can be invoked: when there is no current executor present, or if all other comparisons have failed.
129-
For more details on the executor comparison logic you can refer to [SE-0392: Custom Actor Executors'](https://github.com/apple/swift-evolution/blob/main/proposals/0392-custom-actor-executors.md).
127+
This pseudo code snippet explains the flow of the executor comparisons. There are two situations in which the new `checkIsolated` method may be invoked: when there is no current executor present, or if all other comparisons have failed.
128+
For more details on the executor comparison logic, you can refer to [SE-0392: Custom Actor Executors](https://github.com/apple/swift-evolution/blob/main/proposals/0392-custom-actor-executors.md).
130129

131130
Specific use-cases of this API include `DispatchSerialQueue`, which would be able to implement the requirement as follows:
132131

@@ -166,15 +165,7 @@ actor Worker {
166165

167166
As such, there is no negative impact on the correctness of these APIs.
168167

169-
Asynchronous functions should not use dyanamic isolation checking. Isolation
170-
checking is useful in synchronous functions because they naturally inherit
171-
execution properties like their caller's isolation without disturbing it.
172-
A synchronous function may be formally non-isolated and yet actually
173-
run in an isolated context dynamically. This is not true for asynchronous
174-
functions, which switch to their formal isolation on entry without regard
175-
to their caller's isolation. If an asynchronous function is not formally
176-
isolated to an actor, its execution will never be dynamically in an
177-
isolated context, so there's no point in checking for it.
168+
Asynchronous functions should not use dyanamic isolation checking. Isolation checking is useful in synchronous functions because they naturally inherit execution properties like their caller's isolation without disturbing it. A synchronous function may be formally non-isolated and yet actually run in an isolated context dynamically. This is not true for asynchronous functions, which switch to their formal isolation on entry without regard to their caller's isolation. If an asynchronous function is not formally isolated to an actor, its execution will never be dynamically in an isolated context, so there's no point in checking for it.
178169

179170
## Future directions
180171

@@ -211,11 +202,6 @@ This would allow the isolation model to support different kinds of main executor
211202

212203
### Do not provide customization points, and just hardcode DispatchQueue handling
213204

214-
Alternatively, we could harcode detecting dispatch queues and triggering `dispatchPrecondition` from within the Swift runtime.
205+
Alternatively, we could hardcode detecting dispatch queues and triggering `dispatchPrecondition` from within the Swift runtime.
215206

216207
This is not a good direction though, as our goal is to have the concurrency runtime be less attached to Dispatch and allow Swift to handle each and every execution environment equally well. As such, introducing necessary hooks as official and public API is the way to go here.
217-
218-
219-
## Revisions
220-
- 1.0
221-
- initial revision

0 commit comments

Comments
 (0)