mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
155 lines
6.3 KiB
Swift
155 lines
6.3 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2020 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
import Swift
|
|
@_implementationOnly import SwiftConcurrencyInternalShims
|
|
|
|
// ==== Task Priority Escalation -----------------------------------------------
|
|
|
|
@available(SwiftStdlib 6.2, *)
|
|
extension Task {
|
|
/// Manually escalate the task `priority` of this task to the `newPriority`.
|
|
///
|
|
/// - Warning: This API should rarely be used, and instead you can rely on
|
|
/// structured concurrency and implicit priority escalation which happens
|
|
/// when a higher priority task awaits on a result of a lower priority task.
|
|
///
|
|
/// I.e. using `await` on the target task usually is the correct way to
|
|
/// escalate the target task to the current priority of the calling task,
|
|
/// especially because in such setup if the waiting task gets escalated,
|
|
/// the waited on task would be escalated automatically as well.
|
|
///
|
|
/// The concurrency runtime is free to interpret and handle escalation
|
|
/// depending on platform characteristics.
|
|
///
|
|
/// Priority escalation is propagated to child tasks of the waited-on task,
|
|
/// and will trigger any priority escalation handlers, if any were registered.
|
|
///
|
|
/// Escalation can only *increase* the priority of a task, and
|
|
/// de-escalating priority is not supported.
|
|
///
|
|
/// This method can be called from any task or thread.
|
|
///
|
|
/// - Parameters:
|
|
/// - task: the task which to escalate the priority of
|
|
/// - newPriority: the new priority the task should continue executing on
|
|
@available(SwiftStdlib 6.2, *)
|
|
public func escalatePriority(to newPriority: TaskPriority) {
|
|
_taskEscalate(self._task, newPriority: newPriority.rawValue)
|
|
}
|
|
}
|
|
|
|
@available(SwiftStdlib 6.2, *)
|
|
extension UnsafeCurrentTask {
|
|
/// Escalate the task `priority` of the passed in task to the `newPriority`.
|
|
///
|
|
/// - Warning: This API should rarely be used, and instead you can rely on
|
|
/// structured concurrency and implicit priority escalation which happens
|
|
/// when a higher priority task awaits on a result of a lower priority task.
|
|
///
|
|
/// I.e. using `await` on the target task usually is the correct way to
|
|
/// escalate the target task to the current priority of the calling task,
|
|
/// especially because in such setup if the waiting task gets escalated,
|
|
/// the waited on task would be escalated automatically as well.
|
|
///
|
|
/// The concurrency runtime is free to interpret and handle escalation
|
|
/// depending on platform characteristics.
|
|
///
|
|
/// Priority escalation is propagated to child tasks of the waited-on task,
|
|
/// and will trigger any priority escalation handlers, if any were registered.
|
|
///
|
|
/// Escalation can only *increase* the priority of a task, and
|
|
/// de-escalating priority is not supported.
|
|
///
|
|
/// This method can be called from any task or thread.
|
|
///
|
|
/// - Parameters:
|
|
/// - task: the task which to escalate the priority of
|
|
/// - newPriority: the new priority the task should continue executing on
|
|
@available(SwiftStdlib 6.2, *)
|
|
public func escalatePriority(to newPriority: TaskPriority) {
|
|
unsafe _taskEscalate(self._task, newPriority: newPriority.rawValue)
|
|
}
|
|
}
|
|
|
|
// ==== Task Priority Escalation Handlers --------------------------------------
|
|
|
|
/// Runs the passed `operation` while registering a task priority escalation handler.
|
|
/// The handler will be triggered concurrently to the current task if the current
|
|
/// is subject to priority escalation.
|
|
///
|
|
/// The handler may perform additional actions upon priority escalation,
|
|
/// but cannot influence how the escalation influences the task, i.e. the task's
|
|
/// priority will be escalated regardless of actions performed in the handler.
|
|
///
|
|
/// The handler will only trigger if a priority escalation occurs while the
|
|
/// operation is in progress.
|
|
///
|
|
/// If multiple task escalation handlers are nested they will all be triggered.
|
|
///
|
|
/// Task escalation propagates through structured concurrency child-tasks.
|
|
///
|
|
/// - Parameters:
|
|
/// - operation: the operation during which to listen for priority escalation
|
|
/// - handler: handler to invoke, concurrently to `operation`,
|
|
/// when priority escalation happens
|
|
/// - Returns: the value returned by `operation`
|
|
/// - Throws: when the `operation` throws an error
|
|
@available(SwiftStdlib 6.2, *)
|
|
public func withTaskPriorityEscalationHandler<T, E>(
|
|
operation: () async throws(E) -> T,
|
|
onPriorityEscalated handler: @Sendable (TaskPriority, TaskPriority) -> Void,
|
|
isolation: isolated (any Actor)? = #isolation
|
|
) async throws(E) -> T {
|
|
return try await __withTaskPriorityEscalationHandler0(
|
|
operation: operation,
|
|
onPriorityEscalated: {
|
|
handler(TaskPriority(rawValue: $0), TaskPriority(rawValue: $1))
|
|
})
|
|
}
|
|
|
|
// Method necessary in order to avoid the handler0 to be destroyed too eagerly.
|
|
@available(SwiftStdlib 6.2, *)
|
|
@_alwaysEmitIntoClient
|
|
func __withTaskPriorityEscalationHandler0<T, E>(
|
|
operation: () async throws(E) -> T,
|
|
onPriorityEscalated handler0: @Sendable (UInt8, UInt8) -> Void,
|
|
isolation: isolated (any Actor)? = #isolation
|
|
) async throws(E) -> T {
|
|
#if $BuiltinConcurrencyStackNesting
|
|
let record =
|
|
unsafe Builtin.taskAddPriorityEscalationHandler(handler: handler0)
|
|
defer {
|
|
unsafe Builtin.taskRemovePriorityEscalationHandler(record: record)
|
|
}
|
|
#else
|
|
let record = unsafe _taskAddPriorityEscalationHandler(handler: handler0)
|
|
defer { unsafe _taskRemovePriorityEscalationHandler(record: record) }
|
|
#endif
|
|
|
|
return try await operation()
|
|
}
|
|
|
|
@usableFromInline
|
|
@available(SwiftStdlib 6.2, *)
|
|
@_silgen_name("swift_task_addPriorityEscalationHandler")
|
|
func _taskAddPriorityEscalationHandler(
|
|
handler: (UInt8, UInt8) -> Void
|
|
) -> UnsafeRawPointer /*EscalationNotificationStatusRecord*/
|
|
|
|
@usableFromInline
|
|
@available(SwiftStdlib 6.2, *)
|
|
@_silgen_name("swift_task_removePriorityEscalationHandler")
|
|
func _taskRemovePriorityEscalationHandler(
|
|
record: UnsafeRawPointer /*EscalationNotificationStatusRecord*/
|
|
)
|