@@ -122,6 +122,12 @@ _swift_task_getDispatchQueueSerialExecutorWitnessTable() {
122
122
}
123
123
#endif
124
124
125
+ // The task listed as argument is escalated to a new priority. Pass that
126
+ // inforamtion along to the executor that it is enqueued into.
127
+ SWIFT_CC (swift)
128
+ void
129
+ swift_executor_escalate (ExecutorRef executor, AsyncTask *task, JobPriority newPriority);
130
+
125
131
/* ************** Methods for Status records manipulation ******************/
126
132
127
133
// / Add a status record to the input task.
@@ -839,17 +845,19 @@ inline void AsyncTask::flagAsRunning() {
839
845
840
846
if (!oldStatus.hasTaskDependency ()) {
841
847
SWIFT_TASK_DEBUG_LOG (" %p->flagAsRunning() with no task dependency" , this );
848
+ assert (_private ().dependencyRecord == nullptr );
849
+
842
850
while (true ) {
843
851
#if SWIFT_CONCURRENCY_ENABLE_PRIORITY_ESCALATION
844
- // Task's priority is greater than the thread's - do a self escalation
845
- qos_class_t maxTaskPriority = (qos_class_t ) oldStatus.getStoredPriority ();
846
- if (threadOverrideInfo.can_override && (maxTaskPriority > overrideFloor)) {
847
- SWIFT_TASK_DEBUG_LOG (" [Override] Self-override thread with oq_floor %#x to match task %p's max priority %#x" ,
848
- overrideFloor, this , maxTaskPriority);
849
-
850
- (void ) swift_dispatch_thread_override_self (maxTaskPriority);
851
- overrideFloor = maxTaskPriority;
852
- }
852
+ // Task's priority is greater than the thread's - do a self escalation
853
+ qos_class_t maxTaskPriority = (qos_class_t ) oldStatus.getStoredPriority ();
854
+ if (threadOverrideInfo.can_override && (maxTaskPriority > overrideFloor)) {
855
+ SWIFT_TASK_DEBUG_LOG (" [Override] Self-override thread with oq_floor %#x to match task %p's max priority %#x" ,
856
+ overrideFloor, this , maxTaskPriority);
857
+
858
+ (void ) swift_dispatch_thread_override_self (maxTaskPriority);
859
+ overrideFloor = maxTaskPriority;
860
+ }
853
861
#endif
854
862
// Set self as executor and remove escalation bit if any - the task's
855
863
// priority escalation has already been reflected on the thread.
@@ -923,83 +931,75 @@ inline void AsyncTask::flagAsRunning() {
923
931
inline void AsyncTask::flagAsAndEnqueueOnExecutor (ExecutorRef newExecutor) {
924
932
#if SWIFT_CONCURRENCY_TASK_TO_THREAD_MODEL
925
933
assert (false && " Should not enqueue any tasks to execute in task-to-thread model" );
926
- #else
934
+ #else /* SWIFT_CONCURRENCY_TASK_TO_THREAD_MODEL */
927
935
auto oldStatus = _private ()._status ().load (std::memory_order_relaxed);
928
- JobPriority priority = JobPriority::Unspecified;
929
-
930
- if (oldStatus.isRunning ()) {
931
- SWIFT_TASK_DEBUG_LOG (" %p->flagAsAndEnqueueOnExecutor() running to enqueued" , this );
932
- // Case 1:
933
- // running -> enqueued
934
- // Most likely due to task running into actor contention
935
- // TODO: Need to record a new task dependency
936
- while (true ) {
937
- // Drop execution lock and any override the thread might have received as
938
- // a result of executing it previously. Mark the task as being enqueued
939
- auto newStatus = oldStatus.withRunning (false );
940
- newStatus = newStatus.withoutStoredPriorityEscalation ();
941
- newStatus = newStatus.withEnqueued ();
936
+ assert (!oldStatus.isEnqueued ());
942
937
943
- if (_private ()._status ().compare_exchange_weak (oldStatus, newStatus,
944
- /* success */ std::memory_order_relaxed,
945
- /* failure */ std::memory_order_relaxed)) {
946
- newStatus.traceStatusChanged (this );
947
- priority = newStatus.getStoredPriority ();
948
- break ;
949
- }
950
- }
951
- #if SWIFT_CONCURRENCY_ENABLE_PRIORITY_ESCALATION
952
- // The thread was previously running the task, now that we aren't, we need
953
- // to remove any task escalation on the thread as a result of the task.
954
- if (oldStatus.isStoredPriorityEscalated ()) {
955
- SWIFT_TASK_DEBUG_LOG (" [Override] Reset override %#x on thread from task %p" ,
956
- oldStatus.getStoredPriority (), this );
957
- swift_dispatch_lock_override_end ((qos_class_t ) oldStatus.getStoredPriority ());
958
- }
959
- #endif /* SWIFT_CONCURRENCY_ENABLE_PRIORITY_ESCALATION */
960
- swift_task_exitThreadLocalContext ((char *)&_private ().ExclusivityAccessSet [0 ]);
961
- restoreTaskVoucher (this );
962
-
963
- } else if (oldStatus.hasTaskDependency ()) {
964
- // Case 2: suspended -> enqueued
965
- // Subcase 2a: Task had a dependency which is now cleared - remove task
966
- // dependency record and destroy it
967
- auto dependencyRecord = _private ().dependencyRecord ;
938
+ if (!oldStatus.isRunning () && oldStatus.hasTaskDependency ()) {
939
+ // Task went from suspended --> enqueued and has a previous
940
+ // dependency record.
941
+ //
942
+ // Atomically update the existing dependency record with new dependency
943
+ // information.
944
+ TaskDependencyStatusRecord *dependencyRecord = _private ().dependencyRecord ;
968
945
assert (dependencyRecord != nullptr );
969
- SWIFT_TASK_DEBUG_LOG (" %p->flagAsAndEnqueueOnExecutor() suspended to enqueued and remove dependency %p" , this , dependencyRecord);
970
946
971
- removeStatusRecord (this , dependencyRecord, [&](ActiveTaskStatus unused,
972
- ActiveTaskStatus& newStatus) {
947
+ SWIFT_TASK_DEBUG_LOG (" [Dependency] %p->flagAsAndEnqueueOnExecutor() and update dependencyRecord %p" ,
948
+ this , dependencyRecord);
949
+
950
+ updateStatusRecord (this , dependencyRecord, [&] {
951
+
952
+ // Update dependency record to the new dependency
953
+ dependencyRecord->updateDependencyToEnqueuedOn (newExecutor);
954
+
955
+ }, oldStatus, [&](ActiveTaskStatus unused, ActiveTaskStatus &newStatus) {
956
+
957
+ // Remove escalation bits + set enqueued bit
973
958
newStatus = newStatus.withoutStoredPriorityEscalation ();
974
959
newStatus = newStatus.withEnqueued ();
975
- newStatus = newStatus.withoutTaskDependency ();
976
-
977
- priority = newStatus.getStoredPriority ();
960
+ assert (newStatus.hasTaskDependency ());
978
961
});
979
- this ->destroyTaskDependency (dependencyRecord);
980
-
981
962
} else {
982
- // Case 2: suspended -> enqueued
983
- // Subcase 2b: Task is newly created and enqueued to run - no task
984
- // dependency record present
985
- SWIFT_TASK_DEBUG_LOG (" %p->flagAsAndEnqueueOnExecutor() suspended to enqueued with no dependency" , this );
986
- auto newStatus = oldStatus;
987
- while (true ) {
963
+ // 2 subcases:
964
+ // * Task went from running on this thread --> enqueued on executor
965
+ // * Task went from suspended to enqueued on this executor and has no
966
+ // dependency record (Eg. newly created)
967
+ assert (_private ().dependencyRecord == nullptr );
968
+
969
+ void *allocation = _swift_task_alloc_specific (this , sizeof (class TaskDependencyStatusRecord ));
970
+ TaskDependencyStatusRecord *dependencyRecord = _private ().dependencyRecord = ::new (allocation) TaskDependencyStatusRecord (this , newExecutor);
971
+ SWIFT_TASK_DEBUG_LOG (" [Dependency] %p->flagAsAndEnqueueOnExecutor() with dependencyRecord %p" , this ,
972
+ dependencyRecord);
973
+
974
+ addStatusRecord (this , dependencyRecord, oldStatus, [&](ActiveTaskStatus unused,
975
+ ActiveTaskStatus &newStatus) {
976
+
977
+ newStatus = newStatus.withRunning (false );
988
978
newStatus = newStatus.withoutStoredPriorityEscalation ();
989
979
newStatus = newStatus.withEnqueued ();
980
+ newStatus = newStatus.withTaskDependency ();
990
981
991
- if (_private ()._status ().compare_exchange_weak (oldStatus, newStatus,
992
- /* success */ std::memory_order_relaxed,
993
- /* failure */ std::memory_order_relaxed)) {
994
- newStatus.traceStatusChanged (this );
995
- priority = newStatus.getStoredPriority ();
996
- break ;
982
+ return true ;
983
+ });
984
+
985
+ if (oldStatus.isRunning ()) {
986
+ #if SWIFT_CONCURRENCY_ENABLE_PRIORITY_ESCALATION
987
+ // The thread was previously running the task, now that we aren't and
988
+ // we've successfully escalated the thing the task is waiting on. We need
989
+ // to remove any task escalation on the thread as a result of the task.
990
+ if (oldStatus.isStoredPriorityEscalated ()) {
991
+ SWIFT_TASK_DEBUG_LOG (" [Override] Reset override %#x on thread from task %p" ,
992
+ oldStatus.getStoredPriority (), this );
993
+ swift_dispatch_lock_override_end ((qos_class_t ) oldStatus.getStoredPriority ());
997
994
}
995
+ #endif /* SWIFT_CONCURRENCY_ENABLE_PRIORITY_ESCALATION */
996
+ swift_task_exitThreadLocalContext ((char *)&_private ().ExclusivityAccessSet [0 ]);
997
+ restoreTaskVoucher (this );
998
998
}
999
999
}
1000
1000
1001
1001
// Set up task for enqueue to next location by setting the Job priority field
1002
- Flags.setPriority (priority );
1002
+ Flags.setPriority (oldStatus. getStoredPriority () );
1003
1003
concurrency::trace::task_flags_changed (
1004
1004
this , static_cast <uint8_t >(Flags.getPriority ()), Flags.task_isChildTask (),
1005
1005
Flags.task_isFuture (), Flags.task_isGroupChildTask (),
@@ -1036,9 +1036,8 @@ void AsyncTask::flagAsSuspended(TaskDependencyStatusRecord *dependencyStatusReco
1036
1036
// Note that we have to do this escalation while adding the status record
1037
1037
// and not after - we are not guaranteed to be able to have a valid
1038
1038
// reference to the dependencyStatusRecord or its contents, once we have
1039
- // published it in the ActiveTaskStatus.
1040
- SWIFT_TASK_DEBUG_LOG (" [Dependency] Escalate the dependency %p of task %p" ,
1041
- dependencyStatusRecord, this );
1039
+ // published it in the ActiveTaskStatus since someone else could
1040
+ // concurrently made us runnable.
1042
1041
dependencyStatusRecord->performEscalationAction (newStatus.getStoredPriority ());
1043
1042
1044
1043
// Always add the dependency status record
@@ -1062,8 +1061,6 @@ void AsyncTask::flagAsSuspended(TaskDependencyStatusRecord *dependencyStatusReco
1062
1061
1063
1062
inline void AsyncTask::destroyTaskDependency (TaskDependencyStatusRecord *dependencyRecord) {
1064
1063
assert (_private ().dependencyRecord == dependencyRecord);
1065
-
1066
- dependencyRecord->destroy ();
1067
1064
_swift_task_dealloc_specific (this , dependencyRecord);
1068
1065
1069
1066
_private ().dependencyRecord = nullptr ;
@@ -1075,7 +1072,7 @@ inline void AsyncTask::flagAsSuspendedOnTask(AsyncTask *task) {
1075
1072
assert (_private ().dependencyRecord == nullptr );
1076
1073
1077
1074
void *allocation = _swift_task_alloc_specific (this , sizeof (class TaskDependencyStatusRecord ));
1078
- auto record = ::new (allocation) TaskDependencyStatusRecord (task);
1075
+ auto record = ::new (allocation) TaskDependencyStatusRecord (this , task);
1079
1076
SWIFT_TASK_DEBUG_LOG (" [Dependency] Create a dependencyRecord %p for dependency on task %p" , allocation, task);
1080
1077
_private ().dependencyRecord = record;
1081
1078
@@ -1086,7 +1083,7 @@ inline void AsyncTask::flagAsSuspendedOnContinuation(ContinuationAsyncContext *c
1086
1083
assert (_private ().dependencyRecord == nullptr );
1087
1084
1088
1085
void *allocation = _swift_task_alloc_specific (this , sizeof (class TaskDependencyStatusRecord ));
1089
- auto record = ::new (allocation) TaskDependencyStatusRecord (context);
1086
+ auto record = ::new (allocation) TaskDependencyStatusRecord (this , context);
1090
1087
SWIFT_TASK_DEBUG_LOG (" [Dependency] Create a dependencyRecord %p for dependency on continuation %p" , allocation, context);
1091
1088
_private ().dependencyRecord = record;
1092
1089
@@ -1097,7 +1094,7 @@ inline void AsyncTask::flagAsSuspendedOnTaskGroup(TaskGroup *taskGroup) {
1097
1094
assert (_private ().dependencyRecord == nullptr );
1098
1095
1099
1096
void *allocation = _swift_task_alloc_specific (this , sizeof (class TaskDependencyStatusRecord ));
1100
- auto record = ::new (allocation) TaskDependencyStatusRecord (taskGroup);
1097
+ auto record = ::new (allocation) TaskDependencyStatusRecord (this , taskGroup);
1101
1098
SWIFT_TASK_DEBUG_LOG (" [Dependency] Create a dependencyRecord %p for dependency on taskGroup %p" , allocation, taskGroup);
1102
1099
_private ().dependencyRecord = record;
1103
1100
0 commit comments