You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: proposals/NNNN-task-priority-escalation-apis.md
+46-7
Original file line number
Diff line number
Diff line change
@@ -69,19 +69,58 @@ Another example of libraries which may want to reach for manual task priority es
69
69
In order to address the above use-cases, we propose to add a pair of APIs: to react to priority escalation happening within a block of code, and an API to _cause_ a priority escalation without resorting to trickery using creating new tasks whose only purpose is to escalate the priority of some other task:
70
70
71
71
```swift
72
-
let m: Mutex<Task<Void, Never>?>
72
+
enumState {
73
+
caseinitialized
74
+
casetask(Task<Void, Never>)
75
+
casepriority(TaskPriority)
76
+
}
77
+
let m: Mutex<State> = .init(.initialized)
73
78
74
79
awaitwithTaskPriorityEscalationHandler {
75
-
awaitwithCheckedContinuation { cc in
76
-
let t =Task { cc.resume() }
77
-
m.withLock { $0= t }
78
-
} onPriorityEscalated: { newPriority in
79
-
let t = m.withLock { $0 }
80
-
Task.escalatePriority(t, to: newPriority)
80
+
awaitwithCheckedContinuation { cc in
81
+
let task =Task { cc.resume() }
82
+
83
+
let newPriority: TaskPriority?= state.withLock { state -> TaskPriority?in
84
+
defer { state = .task(task) }
85
+
switch state {
86
+
case .initialized:
87
+
returnnil
88
+
case .task:
89
+
preconditionFailure("unreachable")
90
+
case .priority(let priority):
91
+
return priority
92
+
}
93
+
}
94
+
// priority was escalated just before we have store the task in the mutex
95
+
iflet newPriority {
96
+
Task.escalatePriority(task, to: newPriority)
97
+
}
98
+
} onPriorityEscalated: { newPriority in
99
+
state.withLock { state in
100
+
switch state {
101
+
case .initialized, .priority:
102
+
// priority was escalated just before managed to store the task in the mutex
103
+
state = .priority(newPriority)
104
+
case .task(let task):
105
+
Task.escalatePriority(task, to: newPriority)
106
+
}
107
+
}
81
108
}
82
109
}
83
110
```
84
111
112
+
The above snippet handles edge various ordering situations, including the task escalation happening after
113
+
the time the handler is registered but _before_ we managed to create and store the task.
114
+
115
+
If priority escalation happened before the handler was installed, the `Task.currentPriority` will
116
+
also naturally have the escalated value while the operation executes, meaning that the `Task` created
117
+
during the `operation` would naturally _start at_ the appropriate escalated priority, because it inherits the
118
+
outer task's priority by querying Task.currentPriority.
119
+
120
+
In general, task escalation remains a slightly racy affair, we could always observe an escalation "too late" for it to matter,
121
+
and have any meaningful effect on the work's execution, however this API and associated patterns handle most situations which
122
+
we care about in practice.
123
+
85
124
## Detailed design
86
125
87
126
We propose the addition of a task priority escalation handler, similar to task cancellation handlers already present in the concurrency library:
0 commit comments