1+ //===----------------------------------------------------------------------===//
2+ //
3+ // This source file is part of the Swift.org open source project
4+ //
5+ // Copyright (c) 2020 Apple Inc. and the Swift project authors
6+ // Licensed under Apache License v2.0 with Runtime Library Exception
7+ //
8+ // See https://swift.org/LICENSE.txt for license information
9+ // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+ //
11+ //===----------------------------------------------------------------------===//
12+
13+ import Swift
14+ @_implementationOnly import SwiftConcurrencyInternalShims
15+
16+ // ==== Task Priority Escalation -----------------------------------------------
17+
18+ extension Task {
19+ /// Escalate the task `priority` of the passed in task to the `newPriority`.
20+ ///
21+ /// - Warning: This API should rarely be used, and instead you can rely on
22+ /// structured concurrency and implicit priority escalation which happens
23+ /// when a higher priority task awaits on a result of a lower priority task.
24+ ///
25+ /// I.e. using `await` on the target task usually is the correct way to
26+ /// escalate the target task to the current priority of the calling task,
27+ /// especially because in such setup if the waiting task gets escalated,
28+ /// the waited on task would be escalated automatically as well.
29+ ///
30+ /// The concurrency runtime is free to interpret and handle escalation
31+ /// depending on platform characteristics.
32+ ///
33+ /// Priority escalation is propagated to child tasks of the waited-on task,
34+ /// and will trigger any priority escalation handlers, if any were registered.
35+ ///
36+ /// Escalation can only *increase* the priority of a task, and
37+ /// de-escalating priority is not supported.
38+ ///
39+ /// This method can be called from any task or thread.
40+ ///
41+ /// - Parameters:
42+ /// - task: the task which to escalate the priority of
43+ /// - newPriority: the new priority the task should continue executing on
44+ @available ( SwiftStdlib 6 . 2 , * )
45+ public static func escalatePriority( _ task: Task , to newPriority: TaskPriority ) {
46+ _taskEscalate ( task. _task, newPriority: newPriority. rawValue)
47+ }
48+ }
49+
50+ extension UnsafeCurrentTask {
51+ /// Escalate the task `priority` of the passed in task to the `newPriority`.
52+ ///
53+ /// - Warning: This API should rarely be used, and instead you can rely on
54+ /// structured concurrency and implicit priority escalation which happens
55+ /// when a higher priority task awaits on a result of a lower priority task.
56+ ///
57+ /// I.e. using `await` on the target task usually is the correct way to
58+ /// escalate the target task to the current priority of the calling task,
59+ /// especially because in such setup if the waiting task gets escalated,
60+ /// the waited on task would be escalated automatically as well.
61+ ///
62+ /// The concurrency runtime is free to interpret and handle escalation
63+ /// depending on platform characteristics.
64+ ///
65+ /// Priority escalation is propagated to child tasks of the waited-on task,
66+ /// and will trigger any priority escalation handlers, if any were registered.
67+ ///
68+ /// Escalation can only *increase* the priority of a task, and
69+ /// de-escalating priority is not supported.
70+ ///
71+ /// This method can be called from any task or thread.
72+ ///
73+ /// - Parameters:
74+ /// - task: the task which to escalate the priority of
75+ /// - newPriority: the new priority the task should continue executing on
76+ @available ( SwiftStdlib 6 . 2 , * )
77+ public static func escalatePriority( _ task: UnsafeCurrentTask , to newPriority: TaskPriority ) {
78+ _taskEscalate ( task. _task, newPriority: newPriority. rawValue)
79+ }
80+ }
81+
82+ // ==== Task Priority Escalation Handlers --------------------------------------
83+
84+ /// Runs the passed `operation` while registering a task priority escalation handler.
85+ /// The handler will be triggered concurrently to the current task if the current
86+ /// is subject to priority escalation.
87+ ///
88+ /// The handler may perform additional actions upon priority escalation,
89+ /// but cannot influence how the escalation influences the task, i.e. the task's
90+ /// priority will be escalated regardless of actions performed in the handler.
91+ ///
92+ /// The handler will only trigger if a priority escalation occurs while the
93+ /// operation is in progress.
94+ ///
95+ /// If multiple task escalation handlers are nester they will all be triggered.
96+ ///
97+ /// Task escalation propagates through structured concurrency child-tasks.
98+ ///
99+ /// - Parameters:
100+ /// - operation: the operation during which to listen for priority escalation
101+ /// - handler: handler to invoke, concurrently to `operation`,
102+ /// when priority escalation happens
103+ /// - Returns: the value returned by `operation`
104+ /// - Throws: when the `operation` throws an error
105+ @available ( SwiftStdlib 6 . 2 , * )
106+ public func withTaskPriorityEscalationHandler< T, E> (
107+ operation: ( ) async throws ( E) -> T ,
108+ onPriorityEscalated handler: @Sendable ( TaskPriority ) -> Void ,
109+ isolation: isolated ( any Actor ) ? = #isolation
110+ ) async throws ( E) -> T {
111+ // NOTE: We have to create the closure beforehand as otherwise it seems
112+ // the task-local allocator may be used and we end up violating stack-discipline
113+ // when releasing the handler closure vs. the record.
114+ let handler0 : ( UInt8 ) -> Void = {
115+ handler ( TaskPriority ( rawValue: $0) )
116+ }
117+ let record = _taskAddPriorityEscalationHandler ( handler: handler0)
118+ defer { _taskRemovePriorityEscalationHandler ( record: record) }
119+
120+ return try await operation ( )
121+ }
0 commit comments