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