Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions docs/ConcurrencyRuntime.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
## Concurrency Runtime

This is a general guide to help you get started understanding the Swift concurrency runtime.
For high level semantics refer to Swift Evolution proposals, this document is aimed at developers working in the concurrency runtime, and discusses features which are outside of the scope of Swift evolution, such as runtime optimizations and implementation techniques.

### Actors and Executors

Swift's concurrency model is largely based around actors (and tasks).

**Actors** are the primary way of ensuring "isolation".

Actors execute at most one task at any given time. However a task may be suspended while "on" an actor. When this happens, another task may execute on the actor -- this is called "actor reentrancy.

***

### Executor Switching

Swift performs so called "switching" when executing a task and it has to "hop" between different executor (e.g. actors).
If Swift naively enqueued a job every single time we called some async function, the overhead of async functions or actors
would be prohibitive, therefore Swift employs a technique called (actor) switching.

Switching is a runtime optimization, and has no effect on semantic isolation of a program.

For this discussion the two kinds of `Executor` sub-types that matter are:
- `SerialExecutor` which ensures isolation, i.e. it can be used to guarantee the isolation an actor provides - this is why it is "serial"
- `TaskExecutor` which may be used to ensure a task prefers to run on a specific task executor which may be using a specific thread or group of threads. Task executors do not provide isolation.

22 changes: 13 additions & 9 deletions include/swift/ABI/Executor.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,19 @@ class SerialExecutorRef {
}

const char* getIdentityDebugName() const {
return isMainExecutor() ? " (MainActorExecutor)"
: isGeneric() ? (isForSynchronousStart() ? " (GenericExecutor/SynchronousStart)" : " (GenericExecutor)")
: "";
if (isMainExecutor()) {
return " (MainActorExecutor)";
}
if (isDefaultActor()) {
return " (DefaultActor)";
}
if (isGeneric()) {
if (isForSynchronousStart()) {
return " (GenericExecutor/SynchronousStart)";
}
return " (GenericExecutor)";
}
return "";
}

/// Is this the generic executor reference?
Expand Down Expand Up @@ -186,12 +196,6 @@ class SerialExecutorRef {
return reinterpret_cast<const SerialExecutorWitnessTable*>(table);
}

/// Do we have to do any work to start running as the requested
/// executor?
bool mustSwitchToRun(SerialExecutorRef newExecutor) const {
return Identity != newExecutor.Identity;
}

/// Is this executor the main executor?
bool isMainExecutor() const;

Expand Down
Loading