@@ -484,6 +484,18 @@ JobPriority swift::swift_task_basePriority(AsyncTask *task)
484484 return pri;
485485}
486486
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+
487499// / Implementation of task creation.
488500SWIFT_CC (swift)
489501static AsyncTaskAndContext swift_task_create_commonImpl(
@@ -492,10 +504,11 @@ static AsyncTaskAndContext swift_task_create_commonImpl(
492504 const Metadata *futureResultType,
493505 TaskContinuationFunction *function, void *closureContext,
494506 size_t initialContextSize) {
507+
495508 TaskCreateFlags taskCreateFlags (rawTaskCreateFlags);
509+ JobFlags jobFlags (JobKind::Task, JobPriority::Unspecified);
496510
497511 // Propagate task-creation flags to job flags as appropriate.
498- JobFlags jobFlags (JobKind::Task, taskCreateFlags.getCreationPriority ());
499512 jobFlags.task_setIsChildTask (taskCreateFlags.isChildTask ());
500513 if (futureResultType) {
501514 jobFlags.task_setIsFuture (true );
@@ -548,34 +561,85 @@ static AsyncTaskAndContext swift_task_create_commonImpl(
548561 }
549562
550563 AsyncTask *parent = nullptr ;
564+ AsyncTask *currentTask = swift_task_getCurrent ();
551565 if (jobFlags.task_isChildTask ()) {
552- parent = swift_task_getCurrent () ;
566+ parent = currentTask ;
553567 assert (parent != nullptr && " creating a child task with no active task" );
554568 }
555569
556- // Inherit the priority of the currently-executing task if unspecified and
557- // we want to inherit.
558- if (jobFlags.getPriority () == JobPriority::Unspecified &&
559- (jobFlags.task_isChildTask () || taskCreateFlags.inheritContext ())) {
560- AsyncTask *currentTask = parent;
561- if (!currentTask)
562- currentTask = swift_task_getCurrent ();
563-
564- if (currentTask)
565- jobFlags.setPriority (currentTask->getPriority ());
566- else if (taskCreateFlags.inheritContext ())
567- 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.
568631 }
569632
570- // Adjust user-interactive priorities down to user-initiated.
571- if (jobFlags. getPriority () == JobPriority::UserInteractive)
572- jobFlags. setPriority (JobPriority::UserInitiated);
633+ if ( isUnspecified (basePriority)) {
634+ basePriority = JobPriority::Default;
635+ }
573636
574- // If there is still no job priority, use the default priority.
575- if (jobFlags.getPriority () == JobPriority::Unspecified)
576- jobFlags.setPriority (JobPriority::Default);
637+ SWIFT_TASK_DEBUG_LOG (" Task's base priority = %d" , basePriority);
577638
578- JobPriority basePriority = jobFlags.getPriority ();
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);
579643
580644 // Figure out the size of the header.
581645 size_t headerSize = sizeof (AsyncTask);
@@ -669,7 +733,7 @@ static AsyncTaskAndContext swift_task_create_commonImpl(
669733 // Initialize the task so that resuming it will run the given
670734 // function on the initial context.
671735 AsyncTask *task = nullptr ;
672- bool captureCurrentVoucher = taskCreateFlags. copyTaskLocals () || jobFlags. task_isChildTask ( );
736+ bool captureCurrentVoucher = ! taskIsDetached (taskCreateFlags, jobFlags);
673737 if (asyncLet) {
674738 // Initialize the refcount bits to "immortal", so that
675739 // ARC operations don't have any effect on the task.
@@ -710,7 +774,7 @@ static AsyncTaskAndContext swift_task_create_commonImpl(
710774 futureAsyncContextPrefix->indirectResult = futureFragment->getStoragePtr ();
711775 }
712776
713- 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 );
714778
715779 // Initialize the task-local allocator.
716780 initialContext->ResumeParent = reinterpret_cast <TaskContinuationFunction *>(
0 commit comments