Skip to content

Commit 85e4685

Browse files
authored
[Concurrency] Adjust task escalation APIs to SE accepted shapes (#79988)
* [Concurrency] Adjust task escalation APIs to SE accepted shapes * adjust test a little bit * Fix closure lifetime in withTaskPriorityEscalationHandler * avoid bringing workaround func into abi by marking AEIC
1 parent 202effd commit 85e4685

File tree

9 files changed

+112
-83
lines changed

9 files changed

+112
-83
lines changed

include/swift/ABI/MetadataValues.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1740,7 +1740,7 @@ namespace SpecialPointerAuthDiscriminators {
17401740
const uint16_t AsyncContextResume = 0xd707; // = 55047
17411741
const uint16_t AsyncContextYield = 0xe207; // = 57863
17421742
const uint16_t CancellationNotificationFunction = 0x1933; // = 6451
1743-
const uint16_t EscalationNotificationFunction = 0xf59d; // = 62877
1743+
const uint16_t EscalationNotificationFunction = 0x7861; // = 30817
17441744
const uint16_t AsyncThinNullaryFunction = 0x0f08; // = 3848
17451745
const uint16_t AsyncFutureFunction = 0x720f; // = 29199
17461746

include/swift/ABI/TaskStatus.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ class CancellationNotificationStatusRecord : public TaskStatusRecord {
261261
/// subsequently used.
262262
class EscalationNotificationStatusRecord : public TaskStatusRecord {
263263
public:
264-
using FunctionType = SWIFT_CC(swift) void(JobPriority, SWIFT_CONTEXT void *);
264+
using FunctionType = SWIFT_CC(swift) void(JobPriority, JobPriority, SWIFT_CONTEXT void *);
265265

266266
private:
267267
FunctionType *__ptrauth_swift_escalation_notification_function Function;
@@ -273,8 +273,8 @@ class EscalationNotificationStatusRecord : public TaskStatusRecord {
273273
Function(fn), Argument(arg) {
274274
}
275275

276-
void run(JobPriority newPriority) {
277-
Function(newPriority, Argument);
276+
void run(JobPriority oldPriority, JobPriority newPriority) {
277+
Function(oldPriority, newPriority, Argument);
278278
}
279279

280280
static bool classof(const TaskStatusRecord *record) {
@@ -439,7 +439,8 @@ class TaskDependencyStatusRecord : public TaskStatusRecord {
439439
DependentOn.Executor = executor;
440440
}
441441

442-
void performEscalationAction(JobPriority newPriority);
442+
void performEscalationAction(
443+
JobPriority oldPriority, JobPriority newPriority);
443444
};
444445

445446
} // end namespace swift

stdlib/public/Concurrency/Task+PriorityEscalation.swift

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import Swift
1717

1818
@available(SwiftStdlib 6.2, *)
1919
extension Task {
20-
/// Escalate the task `priority` of the passed in task to the `newPriority`.
20+
/// Manually escalate the task `priority` of this task to the `newPriority`.
2121
///
2222
/// - Warning: This API should rarely be used, and instead you can rely on
2323
/// structured concurrency and implicit priority escalation which happens
@@ -43,8 +43,8 @@ extension Task {
4343
/// - task: the task which to escalate the priority of
4444
/// - newPriority: the new priority the task should continue executing on
4545
@available(SwiftStdlib 6.2, *)
46-
public static func escalatePriority(_ task: Task, to newPriority: TaskPriority) {
47-
_taskEscalate(task._task, newPriority: newPriority.rawValue)
46+
public func escalatePriority(to newPriority: TaskPriority) {
47+
_taskEscalate(self._task, newPriority: newPriority.rawValue)
4848
}
4949
}
5050

@@ -76,8 +76,8 @@ extension UnsafeCurrentTask {
7676
/// - task: the task which to escalate the priority of
7777
/// - newPriority: the new priority the task should continue executing on
7878
@available(SwiftStdlib 6.2, *)
79-
public static func escalatePriority(_ task: UnsafeCurrentTask, to newPriority: TaskPriority) {
80-
unsafe _taskEscalate(task._task, newPriority: newPriority.rawValue)
79+
public func escalatePriority(to newPriority: TaskPriority) {
80+
unsafe _taskEscalate(self._task, newPriority: newPriority.rawValue)
8181
}
8282
}
8383

@@ -107,15 +107,24 @@ extension UnsafeCurrentTask {
107107
@available(SwiftStdlib 6.2, *)
108108
public func withTaskPriorityEscalationHandler<T, E>(
109109
operation: () async throws(E) -> T,
110-
onPriorityEscalated handler: @Sendable (TaskPriority) -> Void,
110+
onPriorityEscalated handler: @Sendable (TaskPriority, TaskPriority) -> Void,
111+
isolation: isolated (any Actor)? = #isolation
112+
) async throws(E) -> T {
113+
return try await __withTaskPriorityEscalationHandler0(
114+
operation: operation,
115+
onPriorityEscalated: {
116+
handler(TaskPriority(rawValue: $0), TaskPriority(rawValue: $1))
117+
})
118+
}
119+
120+
// Method necessary in order to avoid the handler0 to be destroyed too eagerly.
121+
@available(SwiftStdlib 6.2, *)
122+
@_alwaysEmitIntoClient
123+
func __withTaskPriorityEscalationHandler0<T, E>(
124+
operation: () async throws(E) -> T,
125+
onPriorityEscalated handler0: @Sendable (UInt8, UInt8) -> Void,
111126
isolation: isolated (any Actor)? = #isolation
112127
) async throws(E) -> T {
113-
// NOTE: We have to create the closure beforehand as otherwise it seems
114-
// the task-local allocator may be used and we end up violating stack-discipline
115-
// when releasing the handler closure vs. the record.
116-
let handler0: (UInt8) -> Void = {
117-
handler(TaskPriority(rawValue: $0))
118-
}
119128
let record = unsafe _taskAddPriorityEscalationHandler(handler: handler0)
120129
defer { unsafe _taskRemovePriorityEscalationHandler(record: record) }
121130

stdlib/public/Concurrency/Task.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1430,7 +1430,7 @@ func _enqueueJobGlobalWithDeadline(_ seconds: Int64, _ nanoseconds: Int64,
14301430
@available(SwiftStdlib 6.2, *)
14311431
@_silgen_name("swift_task_addPriorityEscalationHandler")
14321432
func _taskAddPriorityEscalationHandler(
1433-
handler: (UInt8) -> Void
1433+
handler: (UInt8, UInt8) -> Void
14341434
) -> UnsafeRawPointer /*EscalationNotificationStatusRecord*/
14351435

14361436
@usableFromInline

stdlib/public/Concurrency/TaskPrivate.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1125,7 +1125,9 @@ void AsyncTask::flagAsSuspended(TaskDependencyStatusRecord *dependencyStatusReco
11251125
// reference to the dependencyStatusRecord or its contents, once we have
11261126
// published it in the ActiveTaskStatus since someone else could
11271127
// concurrently made us runnable.
1128-
dependencyStatusRecord->performEscalationAction(newStatus.getStoredPriority());
1128+
dependencyStatusRecord->performEscalationAction(
1129+
oldStatus.getStoredPriority(),
1130+
newStatus.getStoredPriority());
11291131

11301132
// Always add the dependency status record
11311133
return true;

stdlib/public/Concurrency/TaskStatus.cpp

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,6 +1047,7 @@ static void swift_task_cancelImpl(AsyncTask *task) {
10471047

10481048
/// Perform any escalation actions required by the given record.
10491049
static void performEscalationAction(TaskStatusRecord *record,
1050+
JobPriority oldPriority,
10501051
JobPriority newPriority) {
10511052
switch (record->getKind()) {
10521053
// Child tasks need to be recursively escalated.
@@ -1067,15 +1068,17 @@ static void performEscalationAction(TaskStatusRecord *record,
10671068
case TaskStatusRecordKind::EscalationNotification: {
10681069
auto notification =
10691070
cast<EscalationNotificationStatusRecord>(record);
1070-
notification->run(newPriority);
1071+
SWIFT_TASK_DEBUG_LOG("[Dependency] Trigger task escalation handler record %p, escalate from %#x to %#x",
1072+
record, oldPriority, newPriority);
1073+
notification->run(oldPriority, newPriority);
10711074
return;
10721075
}
10731076

10741077
case TaskStatusRecordKind::TaskDependency: {
10751078
auto dependencyRecord = cast<TaskDependencyStatusRecord>(record);
1076-
SWIFT_TASK_DEBUG_LOG("[Dependency] Escalating a task dependency record %p to %#x",
1077-
record, newPriority);
1078-
dependencyRecord->performEscalationAction(newPriority);
1079+
SWIFT_TASK_DEBUG_LOG("[Dependency] Escalating a task dependency record %p from %#x to %#x",
1080+
record, oldPriority, newPriority);
1081+
dependencyRecord->performEscalationAction(oldPriority, newPriority);
10791082
return;
10801083
}
10811084

@@ -1101,17 +1104,17 @@ static void performEscalationAction(TaskStatusRecord *record,
11011104
SWIFT_CC(swift)
11021105
JobPriority
11031106
static swift_task_escalateImpl(AsyncTask *task, JobPriority newPriority) {
1104-
11051107
SWIFT_TASK_DEBUG_LOG("Escalating %p to %#zx priority", task, newPriority);
11061108
auto oldStatus = task->_private()._status().load(std::memory_order_relaxed);
1109+
auto oldPriority = oldStatus.getStoredPriority();
11071110
auto newStatus = oldStatus;
11081111

11091112
while (true) {
11101113
// Fast path: check that the stored priority is already at least
11111114
// as high as the desired priority.
1112-
if (oldStatus.getStoredPriority() >= newPriority) {
1113-
SWIFT_TASK_DEBUG_LOG("Task is already at %#zx priority", oldStatus.getStoredPriority());
1114-
return oldStatus.getStoredPriority();
1115+
if (oldPriority >= newPriority) {
1116+
SWIFT_TASK_DEBUG_LOG("Task is already at %#zx priority", oldPriority);
1117+
return oldPriority;
11151118
}
11161119

11171120
if (oldStatus.isRunning() || oldStatus.isEnqueued()) {
@@ -1145,8 +1148,11 @@ static swift_task_escalateImpl(AsyncTask *task, JobPriority newPriority) {
11451148
taskStatus = (ActiveTaskStatus *) &task->_private()._status();
11461149
executionLock = (dispatch_lock_t *) ((char*)taskStatus + ActiveTaskStatus::executionLockOffset());
11471150

1148-
SWIFT_TASK_DEBUG_LOG("[Override] Escalating %p which is running on %#x to %#x", task, newStatus.currentExecutionLockOwner(), newPriority);
1149-
swift_dispatch_lock_override_start_with_debounce(executionLock, newStatus.currentExecutionLockOwner(), (qos_class_t) newPriority);
1151+
SWIFT_TASK_DEBUG_LOG("[Override] Escalating %p which is running on %#x from %#x to %#x",
1152+
task, newStatus.currentExecutionLockOwner(),
1153+
oldPriority, newPriority);
1154+
swift_dispatch_lock_override_start_with_debounce(
1155+
executionLock, newStatus.currentExecutionLockOwner(), (qos_class_t) newPriority);
11501156
#endif
11511157
} else if (newStatus.isEnqueued()) {
11521158
// Task is not running, it's enqueued somewhere waiting to be run
@@ -1165,22 +1171,24 @@ static swift_task_escalateImpl(AsyncTask *task, JobPriority newPriority) {
11651171
return newStatus.getStoredPriority();
11661172
}
11671173

1168-
SWIFT_TASK_DEBUG_LOG("[Override] Escalating %p which is suspended to %#x", task, newPriority);
1174+
SWIFT_TASK_DEBUG_LOG("[Override] Escalating %p which is suspended from %#x to %#x",
1175+
task, oldPriority, newPriority);
11691176
// We must have at least one record - the task dependency one.
11701177
assert(newStatus.getInnermostRecord() != NULL);
11711178

11721179
withStatusRecordLock(task, newStatus, [&](ActiveTaskStatus status) {
11731180
// We know that none of the escalation actions will recursively
11741181
// modify the task status record list by adding or removing task records
11751182
for (auto cur: status.records()) {
1176-
performEscalationAction(cur, newPriority);
1183+
performEscalationAction(cur, oldPriority, newPriority);
11771184
}
11781185
});
11791186

11801187
return newStatus.getStoredPriority();
11811188
}
11821189

1183-
void TaskDependencyStatusRecord::performEscalationAction(JobPriority newPriority) {
1190+
void TaskDependencyStatusRecord::performEscalationAction(
1191+
JobPriority oldPriority, JobPriority newPriority) {
11841192
switch (this->DependencyKind) {
11851193
case WaitingOnTask:
11861194
SWIFT_TASK_DEBUG_LOG("[Dependency] Escalate dependent task %p noted in %p record",
@@ -1202,8 +1210,8 @@ void TaskDependencyStatusRecord::performEscalationAction(JobPriority newPriority
12021210
this->DependentOn.TaskGroup, this);
12031211
break;
12041212
case EnqueuedOnExecutor:
1205-
SWIFT_TASK_DEBUG_LOG("[Dependency] Escalate dependent executor %p noted in %p record",
1206-
this->DependentOn.Executor, this);
1213+
SWIFT_TASK_DEBUG_LOG("[Dependency] Escalate dependent executor %p noted in %p record from %#x to %#x",
1214+
this->DependentOn.Executor, this, oldPriority, newPriority);
12071215
swift_executor_escalate(this->DependentOn.Executor, this->WaitingTask, newPriority);
12081216
break;
12091217
}

0 commit comments

Comments
 (0)