mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Through various means, it is possible for a synchronous actor-isolated function to escape to another concurrency domain and be called from outside the actor. The problem existed previously, but has become far easier to trigger now that `@escaping` closures and local functions can be actor-isolated. Introduce runtime detection of such data races, where a synchronous actor-isolated function ends up being called from the wrong executor. Do this by emitting an executor check in actor-isolated synchronous functions, where we query the executor in thread-local storage and ensure that it is what we expect. If it isn't, the runtime complains. The runtime's complaints can be controlled with the environment variable `SWIFT_UNEXPECTED_EXECUTOR_LOG_LEVEL`: 0 - disable checking 1 - warn when a data race is detected 2 - error and abort when a data race is detected At an implementation level, this introduces a new concurrency runtime entry point `_checkExpectedExecutor` that checks the given executor (on which the function should always have been called) against the executor on which is called (which is in thread-local storage). There is a special carve-out here for `@MainActor` code, where we check against the OS's notion of "main thread" as well, so that `@MainActor` code can be called via (e.g.) the Dispatch library's `DispatchQueue.main.async`. The new SIL instruction `extract_executor` performs the lowering of an actor down to its executor, which is implicit in the `hop_to_executor` instruction. Extend the LowerHopToExecutor pass to perform said lowering.
31 lines
1.4 KiB
Swift
31 lines
1.4 KiB
Swift
// RUN: %target-swift-frontend -emit-silgen %s -module-name test -swift-version 5 -enable-experimental-concurrency | %FileCheck --enable-var-scope %s --check-prefix=CHECK-RAW
|
|
// RUN: %target-swift-frontend -emit-silgen %s -module-name test -swift-version 5 -enable-experimental-concurrency > %t.sil
|
|
// RUN: %target-sil-opt -enable-sil-verify-all %t.sil -lower-hop-to-actor -enable-experimental-concurrency | %FileCheck --enable-var-scope %s --check-prefix=CHECK-CANONICAL
|
|
// REQUIRES: concurrency
|
|
|
|
import Swift
|
|
import _Concurrency
|
|
|
|
// CHECK-RAW-LABEL: sil [ossa] @$s4test11onMainActoryyF
|
|
// CHECK-RAW: extract_executor [[MAIN_ACTOR:%.*]] : $MainActor
|
|
|
|
// CHECK-CANONICAL-LABEL: sil [ossa] @$s4test11onMainActoryyF
|
|
// CHECK-CANONICAL: function_ref @$ss22_checkExpectedExecutor7Builtin15_filenameLength01_E7IsASCII5_line9_executoryBp_BwBi1_BwBetF
|
|
@MainActor public func onMainActor() { }
|
|
|
|
public actor MyActor {
|
|
var counter = 0
|
|
|
|
// CHECK-RAW-LABEL: sil private [ossa] @$s4test7MyActorC10getUpdaterSiycyFSiycfU_
|
|
// CHECK-RAW: extract_executor [[ACTOR:%.*]] : $MyActor
|
|
|
|
// CHECK-CANONICAL-LABEL: sil private [ossa] @$s4test7MyActorC10getUpdaterSiycyFSiycfU_
|
|
// CHECK-CANONICAL: function_ref @$ss22_checkExpectedExecutor7Builtin15_filenameLength01_E7IsASCII5_line9_executoryBp_BwBi1_BwBetF
|
|
public func getUpdater() -> (() -> Int) {
|
|
return {
|
|
self.counter = self.counter + 1
|
|
return self.counter
|
|
}
|
|
}
|
|
}
|