Skip to content

Commit 0b7b565

Browse files
committed
Fix a race condition that caused withTimeout to not escalate the priority of the body
rdar://137678566
1 parent 9e9579d commit 0b7b565

File tree

2 files changed

+8
-4
lines changed

2 files changed

+8
-4
lines changed

Sources/SwiftExtensions/AsyncUtils.swift

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,14 @@ package func withTimeout<T: Sendable>(
176176
_ duration: Duration,
177177
_ body: @escaping @Sendable () async throws -> T
178178
) async throws -> T {
179+
// Get the priority with which to launch the body task here so that we can pass the same priority as the initial
180+
// priority to `withTaskPriorityChangedHandler`. Otherwise, we can get into a race condition where bodyTask gets
181+
// launched with a low priority, then the priority gets elevated before we call with `withTaskPriorityChangedHandler`,
182+
// we thus don't receive a `taskPriorityChanged` and hence never increase the priority of `bodyTask`.
183+
let priority = Task.currentPriority
179184
var mutableTasks: [Task<Void, Error>] = []
180185
let stream = AsyncThrowingStream<T, Error> { continuation in
181-
let bodyTask = Task<Void, Error> {
186+
let bodyTask = Task<Void, Error>(priority: priority) {
182187
do {
183188
let result = try await body()
184189
continuation.yield(result)
@@ -187,7 +192,7 @@ package func withTimeout<T: Sendable>(
187192
}
188193
}
189194

190-
let timeoutTask = Task {
195+
let timeoutTask = Task(priority: priority) {
191196
try await Task.sleep(for: duration)
192197
continuation.yield(with: .failure(TimeoutError()))
193198
bodyTask.cancel()
@@ -197,7 +202,7 @@ package func withTimeout<T: Sendable>(
197202

198203
let tasks = mutableTasks
199204

200-
return try await withTaskPriorityChangedHandler {
205+
return try await withTaskPriorityChangedHandler(initialPriority: priority) {
201206
for try await value in stream {
202207
return value
203208
}

Tests/SKSupportTests/AsyncUtilsTests.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ final class AsyncUtilsTests: XCTestCase {
5252
}
5353

5454
func testWithTimeoutEscalatesPriority() async throws {
55-
try XCTSkipIf(true, "Flakey test: rdar://137640122")
5655
let expectation = self.expectation(description: "Timeout started")
5756
let task = Task(priority: .background) {
5857
// We don't actually hit the timeout. It's just a large value.

0 commit comments

Comments
 (0)