mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Priorities keep shifting since I first wrote this and are apparently different on different OS's and different versions of the same OS. Since the test is checking that entering and exiting tasks doesn't effect the outer-scoped priority, I've set a variable based on the main thread's priories, which should be inherited by the child.
86 lines
2.6 KiB
Swift
86 lines
2.6 KiB
Swift
// RUN: %target-run-simple-swift( -Xfrontend -disable-availability-checking %import-libdispatch -parse-as-library) | %FileCheck --dump-input=always %s
|
|
|
|
// REQUIRES: executable_test
|
|
// REQUIRES: concurrency
|
|
// REQUIRES: libdispatch
|
|
|
|
// rdar://76038845
|
|
// REQUIRES: concurrency_runtime
|
|
// UNSUPPORTED: back_deployment_runtime
|
|
|
|
import Dispatch
|
|
|
|
// Work around the inability of older Swift runtimes to print a task priority.
|
|
extension TaskPriority: CustomStringConvertible {
|
|
public var description: String {
|
|
"TaskPriority(rawValue: \(rawValue))"
|
|
}
|
|
}
|
|
|
|
@available(SwiftStdlib 5.5, *)
|
|
@main struct Main {
|
|
static func main() async {
|
|
print("main priority: \(Task.currentPriority)") // CHECK: main priority: TaskPriority(rawValue: [[#MAIN_PRIORITY:]])
|
|
await test_detach()
|
|
await test_multiple_lo_indirectly_escalated()
|
|
}
|
|
}
|
|
|
|
@available(SwiftStdlib 5.5, *)
|
|
func test_detach() async {
|
|
let a1 = Task.currentPriority
|
|
print("a1: \(a1)") // CHECK: a1: TaskPriority(rawValue: [[#MAIN_PRIORITY]])
|
|
|
|
// Note: remember to detach using a higher priority, otherwise a lower one
|
|
// might be escalated by the get() and we could see `default` in the detached
|
|
// task.
|
|
await detach(priority: .userInitiated) {
|
|
let a2 = Task.currentPriority
|
|
print("a2: \(a2)") // CHECK: a2: TaskPriority(rawValue: 25)
|
|
}.get()
|
|
|
|
await detach(priority: .default) {
|
|
let a3 = Task.currentPriority
|
|
// The priority of 'a3' may either be 21 (default) or elevated to that of
|
|
// the main function, whichever is greater.
|
|
print("a3: \(a3)") // CHECK: a3: TaskPriority(rawValue: [[#max(MAIN_PRIORITY,21)]]
|
|
}.get()
|
|
|
|
let a4 = Task.currentPriority
|
|
print("a4: \(a4)") // CHECK: a4: TaskPriority(rawValue: [[#MAIN_PRIORITY]])
|
|
}
|
|
|
|
@available(SwiftStdlib 5.5, *)
|
|
func test_multiple_lo_indirectly_escalated() async {
|
|
@Sendable
|
|
func loopUntil(priority: TaskPriority) async {
|
|
while (Task.currentPriority != priority) {
|
|
await Task.sleep(1_000_000_000)
|
|
}
|
|
}
|
|
|
|
let z = detach(priority: .background) {
|
|
await loopUntil(priority: .userInitiated)
|
|
}
|
|
let x = detach(priority: .background) {
|
|
_ = await z // waiting on `z`, but it won't complete since we're also background
|
|
await loopUntil(priority: .userInitiated)
|
|
}
|
|
|
|
// detach, don't wait
|
|
detach(priority: .userInitiated) {
|
|
await x // escalates x, which waits on z, so z also escalates
|
|
}
|
|
|
|
// since `_` awaited from userInitiated on `x` we:
|
|
// - boost `x` to `userInitiated`
|
|
// and then since `x` waits on `z`
|
|
// - `z` also gets boosted to `userInitiated`
|
|
// which "unlocks" it, allowing the 'default' `await z` to complete:
|
|
await x
|
|
await z
|
|
print("default done") // CHECK: default done
|
|
}
|
|
|
|
|