@@ -47,17 +47,21 @@ extension Task {
4747
4848 /// Returns the `current` task's priority.
4949 ///
50- /// If no current `Task` is available, returns `Priority.default`.
50+ /// If no current `Task` is available, queries the system to determine the
51+ /// priority at which the current function is running. If the system cannot
52+ /// provide an appropriate priority, returns `Priority.default`.
5153 ///
5254 /// - SeeAlso: `Task.Priority`
5355 /// - SeeAlso: `Task.priority`
5456 public static var currentPriority : Priority {
5557 withUnsafeCurrentTask { task in
56- guard let task = task else {
57- return Priority . default
58+ // If we are running on behalf of a task, use that task's priority.
59+ if let task = task {
60+ return task. priority
5861 }
5962
60- return getJobFlags ( task. _task) . priority
63+ // Otherwise, query the system.
64+ return Task . Priority ( rawValue: _getCurrentThreadPriority ( ) ) ?? . default
6165 }
6266 }
6367
@@ -100,6 +104,8 @@ extension Task {
100104 case `default` = 0x15
101105 case utility = 0x11
102106 case background = 0x09
107+
108+ @available ( * , deprecated, message: " unspecified priority will be removed; use nil " )
103109 case unspecified = 0x00
104110
105111 public static func < ( lhs: Priority , rhs: Priority ) -> Bool {
@@ -108,6 +114,18 @@ extension Task {
108114 }
109115}
110116
117+ @available ( macOS 9999 , iOS 9999 , watchOS 9999 , tvOS 9999 , * )
118+ extension Task . Priority {
119+ /// Downgrade user-interactive to user-initiated.
120+ var _downgradeUserInteractive : Task . Priority {
121+ if self == . userInteractive {
122+ return . userInitiated
123+ }
124+
125+ return self
126+ }
127+ }
128+
111129// ==== Task Handle ------------------------------------------------------------
112130
113131@available ( macOS 9999 , iOS 9999 , watchOS 9999 , tvOS 9999 , * )
@@ -257,13 +275,13 @@ extension Task {
257275 var isAsyncTask : Bool { kind == . task }
258276
259277 /// The priority given to the job.
260- var priority : Priority {
278+ var priority : Priority ? {
261279 get {
262- Priority ( rawValue: ( bits & 0xFF00 ) >> 8 ) !
280+ Priority ( rawValue: ( bits & 0xFF00 ) >> 8 )
263281 }
264282
265283 set {
266- bits = ( bits & ~ 0xFF00 ) | ( newValue. rawValue << 8 )
284+ bits = ( bits & ~ 0xFF00 ) | ( ( newValue? . rawValue ?? 0 ) << 8 )
267285 }
268286 }
269287
@@ -312,6 +330,22 @@ extension Task {
312330 }
313331 }
314332
333+ /// Whether this is a task created by the 'async' operation, which
334+ /// conceptually continues the work of the synchronous code that invokes
335+ /// it.
336+ var isContinuingAsyncTask : Bool {
337+ get {
338+ ( bits & ( 1 << 27 ) ) != 0
339+ }
340+
341+ set {
342+ if newValue {
343+ bits = bits | 1 << 27
344+ } else {
345+ bits = ( bits & ~ ( 1 << 27 ) )
346+ }
347+ }
348+ }
315349 }
316350}
317351
@@ -438,23 +472,37 @@ public func detach<T>(
438472}
439473
440474@discardableResult
441- @_alwaysEmitIntoClient
442475@available ( macOS 9999 , iOS 9999 , watchOS 9999 , tvOS 9999 , * )
443476public func asyncDetached< T> (
444- priority: Task . Priority = . unspecified ,
477+ priority: Task . Priority ? = nil ,
445478 @_implicitSelfCapture operation: __owned @Sendable @escaping ( ) async -> T
446479) -> Task . Handle < T , Never > {
447- return detach ( priority: priority, operation: operation)
480+ return detach ( priority: priority ?? . unspecified , operation: operation)
448481}
449482
450483@discardableResult
451- @_alwaysEmitIntoClient
452484@available ( macOS 9999 , iOS 9999 , watchOS 9999 , tvOS 9999 , * )
453485public func asyncDetached< T> (
454- priority: Task . Priority = . unspecified ,
486+ priority: Task . Priority ? = nil ,
455487 @_implicitSelfCapture operation: __owned @Sendable @escaping ( ) async throws -> T
456488) -> Task . Handle < T , Error > {
457- return detach ( priority: priority, operation: operation)
489+ return detach ( priority: priority ?? . unspecified, operation: operation)
490+ }
491+
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)
458506}
459507
460508/// Run given `operation` as asynchronously in its own top-level task.
@@ -468,46 +516,65 @@ public func asyncDetached<T>(
468516/// does not return a handle to refer to the task.
469517///
470518/// - Parameters:
471- /// - priority: priority of the task. If unspecified, the priority will
472- /// be inherited from the task that is currently executing
473- /// or, if there is none, from the platform's understanding of
474- /// which thread is executing.
519+ /// - priority: priority of the task. If nil, the priority will come from
520+ /// Task.currentPriority.
475521/// - operation: the operation to execute
476522@available ( macOS 9999 , iOS 9999 , watchOS 9999 , tvOS 9999 , * )
477- public func async (
478- priority: Task . Priority = . unspecified,
479- @_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping ( ) async -> Void
480- ) {
481- // Determine the priority at which we should create this task
482- let actualPriority : Task . Priority
483- if priority == . unspecified {
484- actualPriority = withUnsafeCurrentTask { task in
485- // If we are running on behalf of a task,
486- if let task = task {
487- return task. priority
488- }
523+ @discardableResult
524+ public func async < T> (
525+ priority: Task . Priority ? = nil ,
526+ @_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping ( ) async -> T
527+ ) -> Task . Handle < T , Never > {
528+ // Set up the job flags for a new task.
529+ var flags = Task . JobFlags ( )
530+ flags. kind = . task
531+ flags. priority = priority ?? Task . currentPriority. _downgradeUserInteractive
532+ flags. isFuture = true
533+ flags. isContinuingAsyncTask = true
489534
490- return Task . Priority ( rawValue: _getCurrentThreadPriority ( ) ) ?? . unspecified
491- }
492- } else {
493- actualPriority = priority
494- }
535+ // Create the asynchronous task future.
536+ let ( task, _) = Builtin . createAsyncTaskFuture ( flags. bits, operation)
495537
496- let adjustedPriority = actualPriority == . userInteractive
497- ? . userInitiated
498- : actualPriority
538+ // Enqueue the resulting job.
539+ _enqueueJobGlobal ( Builtin . convertTaskToJob ( task) )
540+
541+ return Task . Handle ( task)
542+ }
499543
544+ /// Run given `operation` as asynchronously in its own top-level task.
545+ ///
546+ /// The `async` function should be used when creating asynchronous work
547+ /// that operates on behalf of the synchronous function that calls it.
548+ /// Like `detach`, the async function creates a separate, top-level task.
549+ /// Unlike `detach`, the task creating by `async` inherits the priority and
550+ /// actor context of the caller, so the `operation` is treated more like an
551+ /// asynchronous extension to the synchronous operation. Additionally, `async`
552+ /// does not return a handle to refer to the task.
553+ ///
554+ /// - Parameters:
555+ /// - priority: priority of the task. If nil, the priority will come from
556+ /// Task.currentPriority.
557+ /// - operation: the operation to execute
558+ @available ( macOS 9999 , iOS 9999 , watchOS 9999 , tvOS 9999 , * )
559+ @discardableResult
560+ public func async < T> (
561+ priority: Task . Priority ? = nil ,
562+ @_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping ( ) async throws -> T
563+ ) -> Task . Handle < T , Error > {
500564 // Set up the job flags for a new task.
501565 var flags = Task . JobFlags ( )
502566 flags. kind = . task
503- flags. priority = actualPriority
567+ flags. priority = priority ?? Task . currentPriority . _downgradeUserInteractive
504568 flags. isFuture = true
569+ flags. isContinuingAsyncTask = true
505570
506571 // Create the asynchronous task future.
507572 let ( task, _) = Builtin . createAsyncTaskFuture ( flags. bits, operation)
508573
509574 // Enqueue the resulting job.
510575 _enqueueJobGlobal ( Builtin . convertTaskToJob ( task) )
576+
577+ return Task . Handle ( task)
511578}
512579
513580// ==== Async Handler ----------------------------------------------------------
@@ -656,12 +723,10 @@ public struct UnsafeCurrentTask {
656723
657724 /// Returns the `current` task's priority.
658725 ///
659- /// If no current `Task` is available, returns `Priority.default`.
660- ///
661726 /// - SeeAlso: `Task.Priority`
662727 /// - SeeAlso: `Task.currentPriority`
663728 public var priority : Task . Priority {
664- getJobFlags ( _task) . priority
729+ getJobFlags ( _task) . priority ?? . default
665730 }
666731
667732}
0 commit comments