@@ -767,7 +767,7 @@ class DiscardingTaskGroup: public TaskGroupBase {
767
767
768
768
private:
769
769
// / Resume waiting task with specified error
770
- void resumeWaitingTaskWithError (SwiftError *error, TaskGroupStatus &assumed);
770
+ void resumeWaitingTaskWithError (SwiftError *error, TaskGroupStatus &assumed, bool alreadyDecremented );
771
771
};
772
772
773
773
} // end anonymous namespace
@@ -1179,6 +1179,7 @@ void DiscardingTaskGroup::offer(AsyncTask *completedTask, AsyncContext *context)
1179
1179
1180
1180
auto afterComplete = statusCompletePendingAssumeRelease ();
1181
1181
(void ) afterComplete;
1182
+ bool alreadyDecrementedStatus = true ;
1182
1183
SWIFT_TASK_GROUP_DEBUG_LOG (this , " offer, complete, status:%s" ,
1183
1184
afterComplete.to_string (this ).c_str ());
1184
1185
@@ -1196,18 +1197,18 @@ void DiscardingTaskGroup::offer(AsyncTask *completedTask, AsyncContext *context)
1196
1197
waitQueue.load (std::memory_order_relaxed));
1197
1198
switch (priorErrorItem.getStatus ()) {
1198
1199
case ReadyStatus::RawError:
1199
- resumeWaitingTaskWithError (priorErrorItem.getRawError (this ), assumed);
1200
+ resumeWaitingTaskWithError (priorErrorItem.getRawError (this ), assumed, alreadyDecrementedStatus );
1200
1201
break ;
1201
1202
case ReadyStatus::Error:
1202
- resumeWaitingTask (priorErrorItem.getTask (), assumed, /* hadErrorResult=*/ true , /* alreadyDecremented= */ true );
1203
+ resumeWaitingTask (priorErrorItem.getTask (), assumed, /* hadErrorResult=*/ true , alreadyDecrementedStatus );
1203
1204
break ;
1204
1205
default :
1205
1206
swift_Concurrency_fatalError (0 , " only errors can be stored by a discarding task group, yet it wasn't an error!" );
1206
1207
}
1207
1208
} else {
1208
1209
SWIFT_TASK_GROUP_DEBUG_LOG (this , " offer, last pending task, completing with completedTask:%p, completedTask.error:%d, waitingTask:%p" ,
1209
1210
completedTask, hadErrorResult, waitQueue.load (std::memory_order_relaxed));
1210
- resumeWaitingTask (completedTask, assumed, /* hadErrorResult=*/ hadErrorResult);
1211
+ resumeWaitingTask (completedTask, assumed, /* hadErrorResult=*/ hadErrorResult, alreadyDecrementedStatus );
1211
1212
}
1212
1213
}
1213
1214
@@ -1224,44 +1225,48 @@ void TaskGroupBase::resumeWaitingTask(
1224
1225
auto waitingTask = waitQueue.load (std::memory_order_acquire);
1225
1226
assert (waitingTask && " waitingTask must not be null when attempting to resume it" );
1226
1227
assert (assumed.hasWaitingTask ());
1227
- SWIFT_TASK_GROUP_DEBUG_LOG (this , " resume waiting task = %p, error:%d, complete with = %p" ,
1228
- waitingTask, hadErrorResult, completedTask);
1228
+ SWIFT_TASK_GROUP_DEBUG_LOG (this , " resume waiting task = %p, alreadyDecremented:%d, error:%d, complete with = %p" ,
1229
+ waitingTask, alreadyDecremented, hadErrorResult, completedTask);
1229
1230
while (true ) {
1231
+ SWIFT_TASK_GROUP_DEBUG_LOG (this , " resumeWaitingTask, attempt CAS, waiting task = %p, waitQueue.head = %p, error:%d, complete with = %p" ,
1232
+ waitingTask, waitQueue.load (std::memory_order_relaxed), hadErrorResult, completedTask);
1233
+
1230
1234
// ==== a) run waiting task directly -------------------------------------
1231
- // assert(assumed.pendingTasks(this) && "offered to group with no pending tasks!");
1232
- // We are the "first" completed task to arrive,
1233
- // and since there is a task waiting we immediately claim and complete it.
1234
- if (waitQueue.compare_exchange_strong (
1235
- waitingTask, nullptr ,
1236
- /* success*/ std::memory_order_seq_cst ,
1237
- /* failure*/ std::memory_order_seq_cst )) {
1235
+ // assert(assumed.pendingTasks(this) && "offered to group with no pending tasks!");
1236
+ // We are the "first" completed task to arrive,
1237
+ // and since there is a task waiting we immediately claim and complete it.
1238
+ if (waitQueue.compare_exchange_strong (
1239
+ waitingTask, nullptr ,
1240
+ /* success*/ std::memory_order_release ,
1241
+ /* failure*/ std::memory_order_acquire )) {
1238
1242
1239
1243
#if SWIFT_CONCURRENCY_TASK_TO_THREAD_MODEL
1240
- // In the task-to-thread model, child tasks are always actually
1241
- // run synchronously on the parent task's thread. For task groups
1242
- // specifically, this means that poll() will pick a child task
1243
- // that was added to the group and run it to completion as a
1244
- // subroutine. Therefore, when we enter offer(), we know that
1245
- // the parent task is waiting and we can just return to it.
1246
-
1247
- // The task-to-thread logic in poll() currently expects the child
1248
- // task to enqueue itself instead of just filling in the result in
1249
- // the waiting task. This is a little wasteful; there's no reason
1250
- // we can't just have the parent task set itself up as a waiter.
1251
- // But since it's what we're doing, we basically take the same
1252
- // path as we would if there wasn't a waiter.
1253
- enqueueCompletedTask (completedTask, hadErrorResult);
1254
- return ;
1244
+ // In the task-to-thread model, child tasks are always actually
1245
+ // run synchronously on the parent task's thread. For task groups
1246
+ // specifically, this means that poll() will pick a child task
1247
+ // that was added to the group and run it to completion as a
1248
+ // subroutine. Therefore, when we enter offer(), we know that
1249
+ // the parent task is waiting and we can just return to it.
1250
+
1251
+ // The task-to-thread logic in poll() currently expects the child
1252
+ // task to enqueue itself instead of just filling in the result in
1253
+ // the waiting task. This is a little wasteful; there's no reason
1254
+ // we can't just have the parent task set itself up as a waiter.
1255
+ // But since it's what we're doing, we basically take the same
1256
+ // path as we would if there wasn't a waiter.
1257
+ enqueueCompletedTask (completedTask, hadErrorResult);
1258
+ return ;
1255
1259
1256
1260
#else /* SWIFT_CONCURRENCY_TASK_TO_THREAD_MODEL */
1257
- fprintf (stderr, " [%s:%d](%s) assumed:%s\n " , __FILE_NAME__, __LINE__, __FUNCTION__, assumed.to_string (this ).c_str ());
1258
- fprintf (stderr, " [%s:%d](%s) had:%s\n " , __FILE_NAME__, __LINE__, __FUNCTION__, this ->statusString ().c_str ());
1261
+ if (!alreadyDecremented) {
1262
+ (void ) statusCompletePendingReadyWaiting (assumed);
1263
+ }
1259
1264
1260
- if (alreadyDecremented || statusCompletePendingReadyWaiting (assumed)) {
1261
1265
// Run the task.
1262
1266
auto result = PollResult::get (completedTask, hadErrorResult);
1263
- SWIFT_TASK_GROUP_DEBUG_LOG (this , " resume waiting DONE, task = %p, complete with = %p, status = %s" ,
1264
- waitingTask, completedTask, statusString ().c_str ());
1267
+ SWIFT_TASK_GROUP_DEBUG_LOG (this ,
1268
+ " resume waiting DONE, task = %p, backup = %p, complete with = %p, status = %s" ,
1269
+ waitingTask, backup, completedTask, statusString ().c_str ());
1265
1270
1266
1271
// Remove the child from the task group's running tasks list.
1267
1272
// The parent task isn't currently running (we're about to wake
@@ -1283,8 +1288,10 @@ void TaskGroupBase::resumeWaitingTask(
1283
1288
// TODO: allow the caller to suggest an executor
1284
1289
waitingTask->flagAsAndEnqueueOnExecutor (ExecutorRef::generic ());
1285
1290
return ;
1286
- } // else, try again
1287
- #endif
1291
+ #endif /* SWIFT_CONCURRENCY_TASK_TO_THREAD_MODEL */
1292
+ } else {
1293
+ SWIFT_TASK_GROUP_DEBUG_LOG (this , " CAS failed, task = %p, backup = %p, complete with = %p, status = %s" ,
1294
+ waitingTask, backup, completedTask, statusString ().c_str ());
1288
1295
}
1289
1296
}
1290
1297
swift_Concurrency_fatalError (0 , " should have enqueued and returned." );
@@ -1293,7 +1300,8 @@ void TaskGroupBase::resumeWaitingTask(
1293
1300
// / Must be called while holding the TaskGroup lock.
1294
1301
void DiscardingTaskGroup::resumeWaitingTaskWithError (
1295
1302
SwiftError *error,
1296
- TaskGroupStatus &assumed) {
1303
+ TaskGroupStatus &assumed,
1304
+ bool alreadyDecremented) {
1297
1305
auto waitingTask = waitQueue.load (std::memory_order_acquire);
1298
1306
assert (waitingTask && " cannot resume 'null' waiting task!" );
1299
1307
SWIFT_TASK_GROUP_DEBUG_LOG (this , " resume waiting task = %p, with error = %p" ,
@@ -1327,7 +1335,7 @@ void DiscardingTaskGroup::resumeWaitingTaskWithError(
1327
1335
return ;
1328
1336
1329
1337
#else /* SWIFT_CONCURRENCY_TASK_TO_THREAD_MODEL */
1330
- if (statusCompletePendingReadyWaiting (assumed)) {
1338
+ if (alreadyDecremented || statusCompletePendingReadyWaiting (assumed)) {
1331
1339
// Run the task.
1332
1340
auto result = PollResult::getError (error);
1333
1341
@@ -1567,6 +1575,7 @@ reevaluate_if_taskgroup_has_results:;
1567
1575
waitingTask->flagAsSuspended ();
1568
1576
}
1569
1577
// Put the waiting task at the beginning of the wait queue.
1578
+ SWIFT_TASK_GROUP_DEBUG_LOG (this , " WATCH OUT, SET WAITER ONTO waitQueue.head = %p" , waitQueue.load (std::memory_order_relaxed));
1570
1579
if (waitQueue.compare_exchange_strong (
1571
1580
waitHead, waitingTask,
1572
1581
/* success*/ std::memory_order_release,
@@ -1753,6 +1762,8 @@ PollResult TaskGroupBase::waitAll(SwiftError* bodyError, AsyncTask *waitingTask,
1753
1762
waitingTask->flagAsSuspended ();
1754
1763
}
1755
1764
// Put the waiting task at the beginning of the wait queue.
1765
+ SWIFT_TASK_GROUP_DEBUG_LOG (this , " WATCH OUT, set waiter onto... waitQueue.head = %p" , waitQueue.load (std::memory_order_relaxed));
1766
+
1756
1767
if (waitQueue.compare_exchange_strong (
1757
1768
waitHead, waitingTask,
1758
1769
/* success*/ std::memory_order_release,
0 commit comments