Skip to content

Commit 92dd8ef

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`.
1 parent 67ed437 commit 92dd8ef

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
@@ -2007,6 +2007,7 @@ class JobFlags : public FlagSet<size_t> {
20072007
Task_IsChildTask = 24,
20082008
Task_IsFuture = 25,
20092009
Task_IsGroupChildTask = 26,
2010+
Task_IsContinuingAsyncTask = 27,
20102011
};
20112012

20122013
explicit JobFlags(size_t bits) : FlagSet(bits) {}
@@ -2036,6 +2037,9 @@ class JobFlags : public FlagSet<size_t> {
20362037
FLAGSET_DEFINE_FLAG_ACCESSORS(Task_IsGroupChildTask,
20372038
task_isGroupChildTask,
20382039
task_setIsGroupChildTask)
2040+
FLAGSET_DEFINE_FLAG_ACCESSORS(Task_IsContinuingAsyncTask,
2041+
task_isContinuingAsyncTask,
2042+
task_setIsContinuingAsyncTask)
20392043
};
20402044

20412045
/// Kinds of task status record.

stdlib/public/Concurrency/Task.swift

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

123123
return self
124124
}
125-
126-
/// Adjust the given priority (when it is unspecified) by the current
127-
/// priority Return the current priority that,
128-
var _inheritingContextualPriority: Task.Priority {
129-
if self != .unspecified {
130-
return self
131-
}
132-
133-
return Task.currentPriority._downgradeUserInteractive
134-
}
135125
}
136126

137127
// ==== Task Handle ------------------------------------------------------------
@@ -338,6 +328,22 @@ extension Task {
338328
}
339329
}
340330

331+
/// Whether this is a task created by the 'async' operation, which
332+
/// conceptually continues the work of the synchronous code that invokes
333+
/// it.
334+
var isContinuingAsyncTask: Bool {
335+
get {
336+
(bits & (1 << 27)) != 0
337+
}
338+
339+
set {
340+
if newValue {
341+
bits = bits | 1 << 27
342+
} else {
343+
bits = (bits & ~(1 << 27))
344+
}
345+
}
346+
}
341347
}
342348
}
343349

@@ -483,6 +489,22 @@ public func asyncDetached<T>(
483489
return detach(priority: priority, operation: operation)
484490
}
485491

492+
/// ABI stub while we stage in the new signatures
493+
@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
494+
@usableFromInline
495+
func async(
496+
priority: Task.Priority,
497+
@_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping () async -> Void
498+
) {
499+
let adjustedPriority: Task.Priority?
500+
if priority == .unspecified {
501+
adjustedPriority = nil
502+
} else {
503+
adjustedPriority = priority
504+
}
505+
let _: Task.Handle = async(priority: adjustedPriority, operation: operation)
506+
}
507+
486508
/// Run given `operation` as asynchronously in its own top-level task.
487509
///
488510
/// The `async` function should be used when creating asynchronous work
@@ -494,27 +516,63 @@ public func asyncDetached<T>(
494516
/// does not return a handle to refer to the task.
495517
///
496518
/// - Parameters:
497-
/// - priority: priority of the task. If unspecified, the priority will
498-
/// be inherited from the task that is currently executing
499-
/// or, if there is none, from the platform's understanding of
500-
/// which thread is executing.
519+
/// - priority: priority of the task. If nil, the priority will come from
520+
/// Task.currentPriority.
501521
/// - operation: the operation to execute
502522
@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
503-
public func async(
504-
priority: Task.Priority = .unspecified,
505-
@_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping () async -> Void
506-
) {
523+
public func async<T>(
524+
priority: Task.Priority? = nil,
525+
@_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping () async -> T
526+
) -> Task.Handle<T, Never> {
527+
// Set up the job flags for a new task.
528+
var flags = Task.JobFlags()
529+
flags.kind = .task
530+
flags.priority = priority ?? Task.currentPriority._downgradeUserInteractive
531+
flags.isFuture = true
532+
flags.isContinuingAsyncTask = true
533+
534+
// Create the asynchronous task future.
535+
let (task, _) = Builtin.createAsyncTaskFuture(flags.bits, operation)
536+
537+
// Enqueue the resulting job.
538+
_enqueueJobGlobal(Builtin.convertTaskToJob(task))
539+
540+
return Task.Handle(task)
541+
}
542+
543+
/// Run given `operation` as asynchronously in its own top-level task.
544+
///
545+
/// The `async` function should be used when creating asynchronous work
546+
/// that operates on behalf of the synchronous function that calls it.
547+
/// Like `detach`, the async function creates a separate, top-level task.
548+
/// Unlike `detach`, the task creating by `async` inherits the priority and
549+
/// actor context of the caller, so the `operation` is treated more like an
550+
/// asynchronous extension to the synchronous operation. Additionally, `async`
551+
/// does not return a handle to refer to the task.
552+
///
553+
/// - Parameters:
554+
/// - priority: priority of the task. If nil, the priority will come from
555+
/// Task.currentPriority.
556+
/// - operation: the operation to execute
557+
@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
558+
public func async<T>(
559+
priority: Task.Priority? = nil,
560+
@_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping () async throws -> T
561+
) -> Task.Handle<T, Error> {
507562
// Set up the job flags for a new task.
508563
var flags = Task.JobFlags()
509564
flags.kind = .task
510-
flags.priority = priority._inheritingContextualPriority
565+
flags.priority = priority ?? Task.currentPriority._downgradeUserInteractive
511566
flags.isFuture = true
567+
flags.isContinuingAsyncTask = true
512568

513569
// Create the asynchronous task future.
514570
let (task, _) = Builtin.createAsyncTaskFuture(flags.bits, operation)
515571

516572
// Enqueue the resulting job.
517573
_enqueueJobGlobal(Builtin.convertTaskToJob(task))
574+
575+
return Task.Handle(task)
518576
}
519577

520578
// ==== Async Handler ----------------------------------------------------------

0 commit comments

Comments
 (0)