Skip to content

Commit 73748ab

Browse files
committed
[Concurrency] Make async operation return a task handle.
Per updates to the Structured Concurrency protocol, make the `async` operation (1) overloaded on throwing-ness and (2) return an appropriate `Task.Handle`. (cherry picked from commit 92dd8ef)
1 parent cf7176f commit 73748ab

File tree

2 files changed

+81
-19
lines changed

2 files changed

+81
-19
lines changed

include/swift/ABI/MetadataValues.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2001,6 +2001,7 @@ class JobFlags : public FlagSet<size_t> {
20012001
Task_IsChildTask = 24,
20022002
Task_IsFuture = 25,
20032003
Task_IsGroupChildTask = 26,
2004+
Task_IsContinuingAsyncTask = 27,
20042005
};
20052006

20062007
explicit JobFlags(size_t bits) : FlagSet(bits) {}
@@ -2030,6 +2031,9 @@ class JobFlags : public FlagSet<size_t> {
20302031
FLAGSET_DEFINE_FLAG_ACCESSORS(Task_IsGroupChildTask,
20312032
task_isGroupChildTask,
20322033
task_setIsGroupChildTask)
2034+
FLAGSET_DEFINE_FLAG_ACCESSORS(Task_IsContinuingAsyncTask,
2035+
task_isContinuingAsyncTask,
2036+
task_setIsContinuingAsyncTask)
20332037
};
20342038

20352039
/// Kinds of task status record.

stdlib/public/Concurrency/Task.swift

Lines changed: 77 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -159,16 +159,6 @@ extension Task.Priority {
159159

160160
return self
161161
}
162-
163-
/// Adjust the given priority (when it is unspecified) by the current
164-
/// priority Return the current priority that,
165-
var _inheritingContextualPriority: Task.Priority {
166-
if self != .unspecified {
167-
return self
168-
}
169-
170-
return Task.currentPriority._downgradeUserInteractive
171-
}
172162
}
173163

174164
// ==== Task Handle ------------------------------------------------------------
@@ -389,6 +379,22 @@ extension Task {
389379
}
390380
}
391381

382+
/// Whether this is a task created by the 'async' operation, which
383+
/// conceptually continues the work of the synchronous code that invokes
384+
/// it.
385+
var isContinuingAsyncTask: Bool {
386+
get {
387+
(bits & (1 << 27)) != 0
388+
}
389+
390+
set {
391+
if newValue {
392+
bits = bits | 1 << 27
393+
} else {
394+
bits = (bits & ~(1 << 27))
395+
}
396+
}
397+
}
392398
}
393399
}
394400

@@ -534,6 +540,22 @@ public func asyncDetached<T>(
534540
return detach(priority: priority, operation: operation)
535541
}
536542

543+
/// ABI stub while we stage in the new signatures
544+
@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
545+
@usableFromInline
546+
func async(
547+
priority: Task.Priority,
548+
@_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping () async -> Void
549+
) {
550+
let adjustedPriority: Task.Priority?
551+
if priority == .unspecified {
552+
adjustedPriority = nil
553+
} else {
554+
adjustedPriority = priority
555+
}
556+
let _: Task.Handle = async(priority: adjustedPriority, operation: operation)
557+
}
558+
537559
/// Run given `operation` as asynchronously in its own top-level task.
538560
///
539561
/// The `async` function should be used when creating asynchronous work
@@ -545,27 +567,63 @@ public func asyncDetached<T>(
545567
/// does not return a handle to refer to the task.
546568
///
547569
/// - Parameters:
548-
/// - priority: priority of the task. If unspecified, the priority will
549-
/// be inherited from the task that is currently executing
550-
/// or, if there is none, from the platform's understanding of
551-
/// which thread is executing.
570+
/// - priority: priority of the task. If nil, the priority will come from
571+
/// Task.currentPriority.
552572
/// - operation: the operation to execute
553573
@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
554-
public func async(
555-
priority: Task.Priority = .unspecified,
556-
@_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping () async -> Void
557-
) {
574+
public func async<T>(
575+
priority: Task.Priority? = nil,
576+
@_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping () async -> T
577+
) -> Task.Handle<T, Never> {
578+
// Set up the job flags for a new task.
579+
var flags = Task.JobFlags()
580+
flags.kind = .task
581+
flags.priority = priority ?? Task.currentPriority._downgradeUserInteractive
582+
flags.isFuture = true
583+
flags.isContinuingAsyncTask = true
584+
585+
// Create the asynchronous task future.
586+
let (task, _) = Builtin.createAsyncTaskFuture(flags.bits, operation)
587+
588+
// Enqueue the resulting job.
589+
_enqueueJobGlobal(Builtin.convertTaskToJob(task))
590+
591+
return Task.Handle(task)
592+
}
593+
594+
/// Run given `operation` as asynchronously in its own top-level task.
595+
///
596+
/// The `async` function should be used when creating asynchronous work
597+
/// that operates on behalf of the synchronous function that calls it.
598+
/// Like `detach`, the async function creates a separate, top-level task.
599+
/// Unlike `detach`, the task creating by `async` inherits the priority and
600+
/// actor context of the caller, so the `operation` is treated more like an
601+
/// asynchronous extension to the synchronous operation. Additionally, `async`
602+
/// does not return a handle to refer to the task.
603+
///
604+
/// - Parameters:
605+
/// - priority: priority of the task. If nil, the priority will come from
606+
/// Task.currentPriority.
607+
/// - operation: the operation to execute
608+
@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
609+
public func async<T>(
610+
priority: Task.Priority? = nil,
611+
@_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping () async throws -> T
612+
) -> Task.Handle<T, Error> {
558613
// Set up the job flags for a new task.
559614
var flags = Task.JobFlags()
560615
flags.kind = .task
561-
flags.priority = priority._inheritingContextualPriority
616+
flags.priority = priority ?? Task.currentPriority._downgradeUserInteractive
562617
flags.isFuture = true
618+
flags.isContinuingAsyncTask = true
563619

564620
// Create the asynchronous task future.
565621
let (task, _) = Builtin.createAsyncTaskFuture(flags.bits, operation)
566622

567623
// Enqueue the resulting job.
568624
_enqueueJobGlobal(Builtin.convertTaskToJob(task))
625+
626+
return Task.Handle(task)
569627
}
570628

571629
// ==== Async Handler ----------------------------------------------------------

0 commit comments

Comments
 (0)