@@ -47,17 +47,21 @@ extension Task {
47
47
48
48
/// Returns the `current` task's priority.
49
49
///
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`.
51
53
///
52
54
/// - SeeAlso: `Task.Priority`
53
55
/// - SeeAlso: `Task.priority`
54
56
public static var currentPriority : Priority {
55
57
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
58
61
}
59
62
60
- return getJobFlags ( task. _task) . priority
63
+ // Otherwise, query the system.
64
+ return Task . Priority ( rawValue: _getCurrentThreadPriority ( ) ) ?? . default
61
65
}
62
66
}
63
67
@@ -100,6 +104,8 @@ extension Task {
100
104
case `default` = 0x15
101
105
case utility = 0x11
102
106
case background = 0x09
107
+
108
+ @available ( * , deprecated, message: " unspecified priority will be removed; use nil " )
103
109
case unspecified = 0x00
104
110
105
111
public static func < ( lhs: Priority , rhs: Priority ) -> Bool {
@@ -108,6 +114,18 @@ extension Task {
108
114
}
109
115
}
110
116
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
+
111
129
// ==== Task Handle ------------------------------------------------------------
112
130
113
131
@available ( macOS 9999 , iOS 9999 , watchOS 9999 , tvOS 9999 , * )
@@ -257,13 +275,13 @@ extension Task {
257
275
var isAsyncTask : Bool { kind == . task }
258
276
259
277
/// The priority given to the job.
260
- var priority : Priority {
278
+ var priority : Priority ? {
261
279
get {
262
- Priority ( rawValue: ( bits & 0xFF00 ) >> 8 ) !
280
+ Priority ( rawValue: ( bits & 0xFF00 ) >> 8 )
263
281
}
264
282
265
283
set {
266
- bits = ( bits & ~ 0xFF00 ) | ( newValue. rawValue << 8 )
284
+ bits = ( bits & ~ 0xFF00 ) | ( ( newValue? . rawValue ?? 0 ) << 8 )
267
285
}
268
286
}
269
287
@@ -312,6 +330,22 @@ extension Task {
312
330
}
313
331
}
314
332
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
+ }
315
349
}
316
350
}
317
351
@@ -438,23 +472,37 @@ public func detach<T>(
438
472
}
439
473
440
474
@discardableResult
441
- @_alwaysEmitIntoClient
442
475
@available ( macOS 9999 , iOS 9999 , watchOS 9999 , tvOS 9999 , * )
443
476
public func asyncDetached< T> (
444
- priority: Task . Priority = . unspecified ,
477
+ priority: Task . Priority ? = nil ,
445
478
@_implicitSelfCapture operation: __owned @Sendable @escaping ( ) async -> T
446
479
) -> Task . Handle < T , Never > {
447
- return detach ( priority: priority, operation: operation)
480
+ return detach ( priority: priority ?? . unspecified , operation: operation)
448
481
}
449
482
450
483
@discardableResult
451
- @_alwaysEmitIntoClient
452
484
@available ( macOS 9999 , iOS 9999 , watchOS 9999 , tvOS 9999 , * )
453
485
public func asyncDetached< T> (
454
- priority: Task . Priority = . unspecified ,
486
+ priority: Task . Priority ? = nil ,
455
487
@_implicitSelfCapture operation: __owned @Sendable @escaping ( ) async throws -> T
456
488
) -> 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)
458
506
}
459
507
460
508
/// Run given `operation` as asynchronously in its own top-level task.
@@ -468,46 +516,65 @@ public func asyncDetached<T>(
468
516
/// does not return a handle to refer to the task.
469
517
///
470
518
/// - 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.
475
521
/// - operation: the operation to execute
476
522
@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
489
534
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)
495
537
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
+ }
499
543
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 > {
500
564
// Set up the job flags for a new task.
501
565
var flags = Task . JobFlags ( )
502
566
flags. kind = . task
503
- flags. priority = actualPriority
567
+ flags. priority = priority ?? Task . currentPriority . _downgradeUserInteractive
504
568
flags. isFuture = true
569
+ flags. isContinuingAsyncTask = true
505
570
506
571
// Create the asynchronous task future.
507
572
let ( task, _) = Builtin . createAsyncTaskFuture ( flags. bits, operation)
508
573
509
574
// Enqueue the resulting job.
510
575
_enqueueJobGlobal ( Builtin . convertTaskToJob ( task) )
576
+
577
+ return Task . Handle ( task)
511
578
}
512
579
513
580
// ==== Async Handler ----------------------------------------------------------
@@ -656,12 +723,10 @@ public struct UnsafeCurrentTask {
656
723
657
724
/// Returns the `current` task's priority.
658
725
///
659
- /// If no current `Task` is available, returns `Priority.default`.
660
- ///
661
726
/// - SeeAlso: `Task.Priority`
662
727
/// - SeeAlso: `Task.currentPriority`
663
728
public var priority : Task . Priority {
664
- getJobFlags ( _task) . priority
729
+ getJobFlags ( _task) . priority ?? . default
665
730
}
666
731
667
732
}
0 commit comments