@@ -413,7 +413,7 @@ static void completeTaskWithClosure(SWIFT_ASYNC_CONTEXT AsyncContext *context,
413
413
reinterpret_cast <char *>(context) - sizeof (AsyncContextPrefix));
414
414
415
415
swift_release ((HeapObject *)asyncContextPrefix->closureContext );
416
-
416
+
417
417
// Clean up the rest of the task.
418
418
return completeTaskAndRelease (context, error);
419
419
}
@@ -470,6 +470,32 @@ const void *AsyncTask::getResumeFunctionForLogging() {
470
470
return reinterpret_cast <const void *>(ResumeTask);
471
471
}
472
472
473
+ JobPriority swift::swift_task_currentPriority (AsyncTask *task)
474
+ {
475
+ // This is racey but this is to be used in an API is inherently racey anyways.
476
+ auto oldStatus = task->_private ().Status .load (std::memory_order_relaxed);
477
+ return oldStatus.getStoredPriority ();
478
+ }
479
+
480
+ JobPriority swift::swift_task_basePriority (AsyncTask *task)
481
+ {
482
+ JobPriority pri = task->_private ().BasePriority ;
483
+ SWIFT_TASK_DEBUG_LOG (" Task %p has base priority = %zu" , task, pri);
484
+ return pri;
485
+ }
486
+
487
+ static inline bool isUnspecified (JobPriority priority) {
488
+ return priority == JobPriority::Unspecified;
489
+ }
490
+
491
+ static inline bool taskIsUnstructured (JobFlags jobFlags) {
492
+ return !jobFlags.task_isAsyncLetTask () && !jobFlags.task_isGroupChildTask ();
493
+ }
494
+
495
+ static inline bool taskIsDetached (TaskCreateFlags createFlags, JobFlags jobFlags) {
496
+ return taskIsUnstructured (jobFlags) && !createFlags.copyTaskLocals ();
497
+ }
498
+
473
499
// / Implementation of task creation.
474
500
SWIFT_CC (swift)
475
501
static AsyncTaskAndContext swift_task_create_commonImpl(
@@ -478,10 +504,11 @@ static AsyncTaskAndContext swift_task_create_commonImpl(
478
504
const Metadata *futureResultType,
479
505
TaskContinuationFunction *function, void *closureContext,
480
506
size_t initialContextSize) {
507
+
481
508
TaskCreateFlags taskCreateFlags (rawTaskCreateFlags);
509
+ JobFlags jobFlags (JobKind::Task, JobPriority::Unspecified);
482
510
483
511
// Propagate task-creation flags to job flags as appropriate.
484
- JobFlags jobFlags (JobKind::Task, taskCreateFlags.getPriority ());
485
512
jobFlags.task_setIsChildTask (taskCreateFlags.isChildTask ());
486
513
if (futureResultType) {
487
514
jobFlags.task_setIsFuture (true );
@@ -520,7 +547,7 @@ static AsyncTaskAndContext swift_task_create_commonImpl(
520
547
// of in a FutureFragment.
521
548
hasAsyncLetResultBuffer = true ;
522
549
assert (asyncLet && " Missing async let storage" );
523
-
550
+
524
551
jobFlags.task_setIsAsyncLetTask (true );
525
552
jobFlags.task_setIsChildTask (true );
526
553
break ;
@@ -534,32 +561,85 @@ static AsyncTaskAndContext swift_task_create_commonImpl(
534
561
}
535
562
536
563
AsyncTask *parent = nullptr ;
564
+ AsyncTask *currentTask = swift_task_getCurrent ();
537
565
if (jobFlags.task_isChildTask ()) {
538
- parent = swift_task_getCurrent () ;
566
+ parent = currentTask ;
539
567
assert (parent != nullptr && " creating a child task with no active task" );
540
568
}
541
569
542
- // Inherit the priority of the currently-executing task if unspecified and
543
- // we want to inherit.
544
- if (jobFlags.getPriority () == JobPriority::Unspecified &&
545
- (jobFlags.task_isChildTask () || taskCreateFlags.inheritContext ())) {
546
- AsyncTask *currentTask = parent;
547
- if (!currentTask)
548
- currentTask = swift_task_getCurrent ();
549
-
550
- if (currentTask)
551
- jobFlags.setPriority (currentTask->getPriority ());
552
- else if (taskCreateFlags.inheritContext ())
553
- jobFlags.setPriority (swift_task_getCurrentThreadPriority ());
570
+ // Start with user specified priority at creation time (if any)
571
+ JobPriority basePriority = (taskCreateFlags.getRequestedPriority ());
572
+
573
+ if (taskIsDetached (taskCreateFlags, jobFlags)) {
574
+ SWIFT_TASK_DEBUG_LOG (" Creating a detached task from %p" , currentTask);
575
+ // Case 1: No priority specified
576
+ // Base priority = UN
577
+ // Escalated priority = UN
578
+ // Case 2: Priority specified
579
+ // Base priority = user specified priority
580
+ // Escalated priority = UN
581
+ //
582
+ // Task will be created with max priority = max(base priority, UN) = base
583
+ // priority. We shouldn't need to do any additional manipulations here since
584
+ // basePriority should already be the right value
585
+
586
+ } else if (taskIsUnstructured (jobFlags)) {
587
+ SWIFT_TASK_DEBUG_LOG (" Creating an unstructured task from %p" , currentTask);
588
+
589
+ if (isUnspecified (basePriority)) {
590
+ // Case 1: No priority specified
591
+ // Base priority = Base priority of parent with a UI -> IN downgrade
592
+ // Escalated priority = UN
593
+ if (currentTask) {
594
+ basePriority = currentTask->_private ().BasePriority ;
595
+ } else {
596
+ basePriority = swift_task_getCurrentThreadPriority ();
597
+ }
598
+ basePriority = withUserInteractivePriorityDowngrade (basePriority);
599
+ } else {
600
+ // Case 2: User specified a priority
601
+ // Base priority = user specified priority
602
+ // Escalated priority = UN
603
+ }
604
+
605
+ // Task will be created with max priority = max(base priority, UN) = base
606
+ // priority
607
+ } else {
608
+ // Is a structured concurrency child task. Must have a parent.
609
+ assert ((asyncLet || group) && parent);
610
+ SWIFT_TASK_DEBUG_LOG (" Creating an structured concurrency task from %p" , currentTask);
611
+
612
+ if (isUnspecified (basePriority)) {
613
+ // Case 1: No priority specified
614
+ // Base priority = Base priority of parent with a UI -> IN downgrade
615
+ // Escalated priority = Escalated priority of parent with a UI -> IN
616
+ // downgrade
617
+ JobPriority parentBasePri = parent->_private ().BasePriority ;
618
+ basePriority = withUserInteractivePriorityDowngrade (parentBasePri);
619
+ } else {
620
+ // Case 2: User priority specified
621
+ // Base priority = User specified priority
622
+ // Escalated priority = Escalated priority of parent with a UI -> IN
623
+ // downgrade
624
+ }
625
+
626
+ // Task will be created with escalated priority = base priority. We will
627
+ // update the escalated priority with the right rules in
628
+ // updateNewChildWithParentAndGroupState when we link the child into
629
+ // the parent task/task group since we'll have the right
630
+ // synchronization then.
631
+ }
632
+
633
+ if (isUnspecified (basePriority)) {
634
+ basePriority = JobPriority::Default;
554
635
}
555
636
556
- // Adjust user-interactive priorities down to user-initiated.
557
- if (jobFlags.getPriority () == JobPriority::UserInteractive)
558
- jobFlags.setPriority (JobPriority::UserInitiated);
637
+ SWIFT_TASK_DEBUG_LOG (" Task's base priority = %d" , basePriority);
559
638
560
- // If there is still no job priority, use the default priority.
561
- if (jobFlags.getPriority () == JobPriority::Unspecified)
562
- jobFlags.setPriority (JobPriority::Default);
639
+ // TODO (rokhinip): Figure out the semantics of the job priority and where
640
+ // it ought to be set conclusively - seems like it ought to be at enqueue
641
+ // time. For now, maintain current semantics of setting jobPriority as well.
642
+ jobFlags.setPriority (basePriority);
563
643
564
644
// Figure out the size of the header.
565
645
size_t headerSize = sizeof (AsyncTask);
@@ -591,14 +671,14 @@ static AsyncTaskAndContext swift_task_create_commonImpl(
591
671
void *allocation = nullptr ;
592
672
if (asyncLet) {
593
673
assert (parent);
594
-
674
+
595
675
// If there isn't enough room in the fixed async let allocation to
596
676
// set up the initial context, then we'll have to allocate more space
597
677
// from the parent.
598
678
if (asyncLet->getSizeOfPreallocatedSpace () < amountToAllocate) {
599
679
hasAsyncLetResultBuffer = false ;
600
680
}
601
-
681
+
602
682
// DEPRECATED. This is separated from the above condition because we
603
683
// also have to handle an older async let ABI that did not provide
604
684
// space for the initial slab in the compiler-generated preallocation.
@@ -653,7 +733,7 @@ static AsyncTaskAndContext swift_task_create_commonImpl(
653
733
// Initialize the task so that resuming it will run the given
654
734
// function on the initial context.
655
735
AsyncTask *task = nullptr ;
656
- bool captureCurrentVoucher = taskCreateFlags. copyTaskLocals () || jobFlags. task_isChildTask ( );
736
+ bool captureCurrentVoucher = ! taskIsDetached (taskCreateFlags, jobFlags);
657
737
if (asyncLet) {
658
738
// Initialize the refcount bits to "immortal", so that
659
739
// ARC operations don't have any effect on the task.
@@ -678,7 +758,7 @@ static AsyncTaskAndContext swift_task_create_commonImpl(
678
758
auto groupChildFragment = task->groupChildFragment ();
679
759
new (groupChildFragment) AsyncTask::GroupChildFragment (group);
680
760
}
681
-
761
+
682
762
// Initialize the future fragment if applicable.
683
763
if (futureResultType) {
684
764
assert (task->isFuture ());
@@ -694,7 +774,7 @@ static AsyncTaskAndContext swift_task_create_commonImpl(
694
774
futureAsyncContextPrefix->indirectResult = futureFragment->getStoragePtr ();
695
775
}
696
776
697
- SWIFT_TASK_DEBUG_LOG (" creating task %p with parent %p" , task, parent);
777
+ SWIFT_TASK_DEBUG_LOG (" creating task %p with parent %p at base pri %zu " , task, parent, basePriority );
698
778
699
779
// Initialize the task-local allocator.
700
780
initialContext->ResumeParent = reinterpret_cast <TaskContinuationFunction *>(
@@ -704,9 +784,10 @@ static AsyncTaskAndContext swift_task_create_commonImpl(
704
784
if (asyncLet && initialSlabSize > 0 ) {
705
785
assert (parent);
706
786
void *initialSlab = (char *)allocation + amountToAllocate;
707
- task->Private .initializeWithSlab (task, initialSlab, initialSlabSize);
787
+ task->Private .initializeWithSlab (basePriority, initialSlab,
788
+ initialSlabSize);
708
789
} else {
709
- task->Private .initialize (task );
790
+ task->Private .initialize (basePriority );
710
791
}
711
792
712
793
// Perform additional linking between parent and child task.
@@ -940,7 +1021,7 @@ static AsyncTask *swift_continuation_initImpl(ContinuationAsyncContext *context,
940
1021
// must happen-after this call.
941
1022
context->AwaitSynchronization .store (flags.isPreawaited ()
942
1023
? ContinuationStatus::Awaited
943
- : ContinuationStatus::Pending,
1024
+ : ContinuationStatus::Pending,
944
1025
std::memory_order_relaxed);
945
1026
946
1027
AsyncTask *task;
0 commit comments