Skip to content

[SE-0304] Align Task API implementation with the fourth revision of the proposal #38306

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jul 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions stdlib/public/Concurrency/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ add_swift_target_library(swift_Concurrency ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} I
TaskGroup.swift
TaskLocal.cpp
TaskLocal.swift
TaskSleep.swift
ThreadSanitizer.cpp
Mutex.cpp
AsyncStreamBuffer.swift
Expand Down
2 changes: 0 additions & 2 deletions stdlib/public/Concurrency/PartialAsyncTask.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ import Swift
@frozen
public struct UnownedJob {
private var context: Builtin.Job

public func run() { }
}

@available(SwiftStdlib 5.5, *)
Expand Down
60 changes: 48 additions & 12 deletions stdlib/public/Concurrency/SourceCompatibilityShims.swift
Original file line number Diff line number Diff line change
Expand Up @@ -190,65 +190,101 @@ extension Task where Failure == Never {

@available(SwiftStdlib 5.5, *)
extension TaskGroup {
@available(*, deprecated, renamed: "async(priority:operation:)")
@available(*, deprecated, renamed: "addTask(priority:operation:)")
@_alwaysEmitIntoClient
public mutating func add(
priority: TaskPriority? = nil,
operation: __owned @Sendable @escaping () async -> ChildTaskResult
) async -> Bool {
return self.asyncUnlessCancelled(priority: priority) {
return self.addTaskUnlessCancelled(priority: priority) {
await operation()
}
}

@available(*, deprecated, renamed: "async(priority:operation:)")
@available(*, deprecated, renamed: "addTask(priority:operation:)")
@_alwaysEmitIntoClient
public mutating func spawn(
priority: TaskPriority? = nil,
operation: __owned @Sendable @escaping () async -> ChildTaskResult
) {
async(priority: priority, operation: operation)
addTask(priority: priority, operation: operation)
}

@available(*, deprecated, renamed: "asyncUnlessCancelled(priority:operation:)")
@available(*, deprecated, renamed: "addTaskUnlessCancelled(priority:operation:)")
@_alwaysEmitIntoClient
public mutating func spawnUnlessCancelled(
priority: TaskPriority? = nil,
operation: __owned @Sendable @escaping () async -> ChildTaskResult
) -> Bool {
asyncUnlessCancelled(priority: priority, operation: operation)
addTaskUnlessCancelled(priority: priority, operation: operation)
}

@available(*, deprecated, renamed: "addTask(priority:operation:)")
@_alwaysEmitIntoClient
public mutating func async(
priority: TaskPriority? = nil,
operation: __owned @Sendable @escaping () async -> ChildTaskResult
) {
addTask(priority: priority, operation: operation)
}

@available(*, deprecated, renamed: "addTaskUnlessCancelled(priority:operation:)")
@_alwaysEmitIntoClient
public mutating func asyncUnlessCancelled(
priority: TaskPriority? = nil,
operation: __owned @Sendable @escaping () async -> ChildTaskResult
) -> Bool {
addTaskUnlessCancelled(priority: priority, operation: operation)
}
}

@available(SwiftStdlib 5.5, *)
extension ThrowingTaskGroup {
@available(*, deprecated, renamed: "async(priority:operation:)")
@available(*, deprecated, renamed: "addTask(priority:operation:)")
@_alwaysEmitIntoClient
public mutating func add(
priority: TaskPriority? = nil,
operation: __owned @Sendable @escaping () async throws -> ChildTaskResult
) async -> Bool {
return self.asyncUnlessCancelled(priority: priority) {
return self.addTaskUnlessCancelled(priority: priority) {
try await operation()
}
}

@available(*, deprecated, renamed: "async(priority:operation:)")
@available(*, deprecated, renamed: "addTask(priority:operation:)")
@_alwaysEmitIntoClient
public mutating func spawn(
priority: TaskPriority? = nil,
operation: __owned @Sendable @escaping () async throws -> ChildTaskResult
) {
async(priority: priority, operation: operation)
addTask(priority: priority, operation: operation)
}

@available(*, deprecated, renamed: "asyncUnlessCancelled(priority:operation:)")
@available(*, deprecated, renamed: "addTaskUnlessCancelled(priority:operation:)")
@_alwaysEmitIntoClient
public mutating func spawnUnlessCancelled(
priority: TaskPriority? = nil,
operation: __owned @Sendable @escaping () async throws -> ChildTaskResult
) -> Bool {
asyncUnlessCancelled(priority: priority, operation: operation)
addTaskUnlessCancelled(priority: priority, operation: operation)
}

@available(*, deprecated, renamed: "addTask(priority:operation:)")
@_alwaysEmitIntoClient
public mutating func async(
priority: TaskPriority? = nil,
operation: __owned @Sendable @escaping () async throws -> ChildTaskResult
) {
addTask(priority: priority, operation: operation)
}

@available(*, deprecated, renamed: "addTaskUnlessCancelled(priority:operation:)")
@_alwaysEmitIntoClient
public mutating func asyncUnlessCancelled(
priority: TaskPriority? = nil,
operation: __owned @Sendable @escaping () async throws -> ChildTaskResult
) -> Bool {
addTaskUnlessCancelled(priority: priority, operation: operation)
}
}

Expand Down
44 changes: 23 additions & 21 deletions stdlib/public/Concurrency/Task.swift
Original file line number Diff line number Diff line change
Expand Up @@ -202,11 +202,20 @@ public struct TaskPriority: RawRepresentable, Sendable {
}

public static let high: TaskPriority = .init(rawValue: 0x19)
public static let userInitiated: TaskPriority = high
public static let `default`: TaskPriority = .init(rawValue: 0x15)

@_alwaysEmitIntoClient
public static var medium: TaskPriority {
.init(rawValue: 0x15)
}

public static let low: TaskPriority = .init(rawValue: 0x11)

public static let userInitiated: TaskPriority = high
public static let utility: TaskPriority = low
public static let background: TaskPriority = .init(rawValue: 0x09)

@available(*, deprecated, renamed: "medium")
public static let `default`: TaskPriority = .init(rawValue: 0x15)
}

@available(SwiftStdlib 5.5, *)
Expand Down Expand Up @@ -606,25 +615,6 @@ extension Task where Failure == Error {
}
}

// ==== Async Sleep ------------------------------------------------------------

@available(SwiftStdlib 5.5, *)
extension Task where Success == Never, Failure == Never {
/// Suspends the current task for _at least_ the given duration
/// in nanoseconds.
///
/// This function does _not_ block the underlying thread.
public static func sleep(_ duration: UInt64) async {
let currentTask = Builtin.getCurrentAsyncTask()
let priority = getJobFlags(currentTask).priority ?? Task.currentPriority._downgradeUserInteractive

return await Builtin.withUnsafeContinuation { (continuation: Builtin.RawUnsafeContinuation) -> Void in
let job = _taskCreateNullaryContinuationJob(priority: Int(priority.rawValue), continuation: continuation)
_enqueueJobGlobalWithDelay(duration, job)
}
}
}

// ==== Voluntary Suspension -----------------------------------------------------

@available(SwiftStdlib 5.5, *)
Expand All @@ -636,6 +626,8 @@ extension Task where Success == Never, Failure == Never {
/// This is not a perfect cure for starvation;
/// if the task is the highest-priority task in the system, it might go
/// immediately back to executing.
///
@available(*, deprecated, renamed: "suspend()")
public static func yield() async {
let currentTask = Builtin.getCurrentAsyncTask()
let priority = getJobFlags(currentTask).priority ?? Task.currentPriority._downgradeUserInteractive
Expand All @@ -645,6 +637,11 @@ extension Task where Success == Never, Failure == Never {
_enqueueJobGlobal(job)
}
}

@_alwaysEmitIntoClient
public static func suspend() async {
await yield()
}
}

// ==== UnsafeCurrentTask ------------------------------------------------------
Expand Down Expand Up @@ -715,6 +712,11 @@ public struct UnsafeCurrentTask {
public var priority: TaskPriority {
getJobFlags(_task).priority ?? .unspecified
}

/// Cancel the current task.
public func cancel() {
_taskCancel(_task)
}
}

@available(SwiftStdlib 5.5, *)
Expand Down
2 changes: 1 addition & 1 deletion stdlib/public/Concurrency/TaskCancellation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ public struct CancellationError: Error {

@available(SwiftStdlib 5.5, *)
@_silgen_name("swift_task_addCancellationHandler")
func _taskAddCancellationHandler(handler: @Sendable () -> Void) -> UnsafeRawPointer /*CancellationNotificationStatusRecord*/
func _taskAddCancellationHandler(handler: () -> Void) -> UnsafeRawPointer /*CancellationNotificationStatusRecord*/

@available(SwiftStdlib 5.5, *)
@_silgen_name("swift_task_removeCancellationHandler")
Expand Down
29 changes: 24 additions & 5 deletions stdlib/public/Concurrency/TaskGroup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ public struct TaskGroup<ChildTaskResult> {
/// - `true` if the operation was added to the group successfully,
/// `false` otherwise (e.g. because the group `isCancelled`)
@_alwaysEmitIntoClient
public mutating func async(
public mutating func addTask(
priority: TaskPriority? = nil,
operation: __owned @Sendable @escaping () async -> ChildTaskResult
) {
Expand Down Expand Up @@ -242,7 +242,7 @@ public struct TaskGroup<ChildTaskResult> {
/// - `true` if the operation was added to the group successfully,
/// `false` otherwise (e.g. because the group `isCancelled`)
@_alwaysEmitIntoClient
public mutating func asyncUnlessCancelled(
public mutating func addTaskUnlessCancelled(
priority: TaskPriority? = nil,
operation: __owned @Sendable @escaping () async -> ChildTaskResult
) -> Bool {
Expand Down Expand Up @@ -333,7 +333,14 @@ public struct TaskGroup<ChildTaskResult> {
internal mutating func awaitAllRemainingTasks() async {
while let _ = await next() {}
}


/// Wait for all remaining tasks in the task group to complete before
/// returning.
@_alwaysEmitIntoClient
public mutating func waitForAll() async {
await awaitAllRemainingTasks()
}

/// Query whether the group has any remaining tasks.
///
/// Task groups are always empty upon entry to the `withTaskGroup` body, and
Expand Down Expand Up @@ -424,6 +431,18 @@ public struct ThrowingTaskGroup<ChildTaskResult, Failure: Error> {
}
}

@usableFromInline
internal mutating func _waitForAll() async throws {
while let _ = try await next() { }
}

/// Wait for all remaining tasks in the task group to complete before
/// returning.
@_alwaysEmitIntoClient
public mutating func waitForAll() async throws {
while let _ = try await next() { }
}

/// Spawn, unconditionally, a child task in the group.
///
/// ### Error handling
Expand All @@ -440,7 +459,7 @@ public struct ThrowingTaskGroup<ChildTaskResult, Failure: Error> {
/// - `true` if the operation was added to the group successfully,
/// `false` otherwise (e.g. because the group `isCancelled`)
@_alwaysEmitIntoClient
public mutating func async(
public mutating func addTask(
priority: TaskPriority? = nil,
operation: __owned @Sendable @escaping () async throws -> ChildTaskResult
) {
Expand Down Expand Up @@ -474,7 +493,7 @@ public struct ThrowingTaskGroup<ChildTaskResult, Failure: Error> {
/// - `true` if the operation was added to the group successfully,
/// `false` otherwise (e.g. because the group `isCancelled`)
@_alwaysEmitIntoClient
public mutating func asyncUnlessCancelled(
public mutating func addTaskUnlessCancelled(
priority: TaskPriority? = nil,
operation: __owned @Sendable @escaping () async throws -> ChildTaskResult
) -> Bool {
Expand Down
Loading