@@ -1238,7 +1238,11 @@ void AccumulatingTaskGroup::offer(AsyncTask *completedTask, AsyncContext *contex
1238
1238
auto prepared = prepareWaitingTaskWithTask (
1239
1239
/* complete=*/ waitingTask, /* with=*/ completedTask,
1240
1240
assumed, hadErrorResult);
1241
- unlock (); // we MUST unlock before running the waiting task
1241
+ // we must unlock before running the waiting task,
1242
+ // in order to avoid the potential for the resumed task
1243
+ // to cause a group destroy, in which case the unlock might
1244
+ // attempt memory in an invalid state.
1245
+ unlock ();
1242
1246
return runWaitingTask (prepared);
1243
1247
} else {
1244
1248
// ==== b) enqueue completion ------------------------------------------------
@@ -1314,7 +1318,11 @@ void DiscardingTaskGroup::offer(AsyncTask *completedTask, AsyncContext *context)
1314
1318
/* complete=*/ waitingTask,
1315
1319
/* with=*/ readyErrorItem.getRawError (this ), assumed,
1316
1320
alreadyDecrementedStatus);
1317
- unlock (); // we MUST unlock before running the waiting task
1321
+ // we must unlock before running the waiting task,
1322
+ // in order to avoid the potential for the resumed task
1323
+ // to cause a group destroy, in which case the unlock might
1324
+ // attempt memory in an invalid state.
1325
+ unlock ();
1318
1326
return runWaitingTask (prepared);
1319
1327
}
1320
1328
case ReadyStatus::Error: {
@@ -1331,7 +1339,11 @@ void DiscardingTaskGroup::offer(AsyncTask *completedTask, AsyncContext *context)
1331
1339
/* with=*/ readyErrorItem.getTask (), assumed,
1332
1340
/* hadErrorResult=*/ true , alreadyDecrementedStatus,
1333
1341
/* taskWasRetained=*/ true );
1334
- unlock (); // we MUST unlock before running the waiting task
1342
+ // we must unlock before running the waiting task,
1343
+ // in order to avoid the potential for the resumed task
1344
+ // to cause a group destroy, in which case the unlock might
1345
+ // attempt memory in an invalid state.
1346
+ unlock ();
1335
1347
return runWaitingTask (prepared);
1336
1348
}
1337
1349
default : {
@@ -1348,7 +1360,11 @@ void DiscardingTaskGroup::offer(AsyncTask *completedTask, AsyncContext *context)
1348
1360
// There was no prior failed task stored, so we should resume the waitingTask with this (failed) completedTask
1349
1361
auto prepared = prepareWaitingTaskWithTask (/* complete=*/ waitingTask, /* with=*/ completedTask,
1350
1362
assumed, hadErrorResult, alreadyDecrementedStatus);
1351
- unlock (); // we MUST unlock before running the waiting task
1363
+ // we must unlock before running the waiting task,
1364
+ // in order to avoid the potential for the resumed task
1365
+ // to cause a group destroy, in which case the unlock might
1366
+ // attempt memory in an invalid state.
1367
+ unlock ();
1352
1368
return runWaitingTask (prepared);
1353
1369
}
1354
1370
} else if (readyQueue.isEmpty ()) {
@@ -1370,7 +1386,7 @@ void DiscardingTaskGroup::offer(AsyncTask *completedTask, AsyncContext *context)
1370
1386
// We grab the waiting task while holding the group lock, because this
1371
1387
// allows a single task to get the waiting task and attempt to complete it.
1372
1388
// As another offer gets to run, it will have either a different waiting task, or no waiting task at all.
1373
- auto waitingTask = waitQueue.load (std::memory_order_acquire);
1389
+ auto waitingTask = waitQueue.load (std::memory_order_acquire);
1374
1390
if (!waitQueue.compare_exchange_strong (waitingTask, nullptr )) {
1375
1391
swift_Concurrency_fatalError (0 , " Failed to claim waitingTask!" );
1376
1392
}
@@ -1391,7 +1407,11 @@ void DiscardingTaskGroup::offer(AsyncTask *completedTask, AsyncContext *context)
1391
1407
auto task = prepareWaitingTaskWithError (
1392
1408
/* complete=*/ waitingTask, /* with=*/ readyErrorItem.getRawError (this ),
1393
1409
assumed, alreadyDecrementedStatus);
1394
- unlock (); // we MUST unlock before running the waiting task
1410
+ // we must unlock before running the waiting task,
1411
+ // in order to avoid the potential for the resumed task
1412
+ // to cause a group destroy, in which case the unlock might
1413
+ // attempt memory in an invalid state.
1414
+ unlock ();
1395
1415
return runWaitingTask (task);
1396
1416
}
1397
1417
case ReadyStatus::Error: {
@@ -1400,7 +1420,11 @@ void DiscardingTaskGroup::offer(AsyncTask *completedTask, AsyncContext *context)
1400
1420
/* with=*/ readyErrorItem.getTask (), assumed,
1401
1421
/* hadErrorResult=*/ true , alreadyDecrementedStatus,
1402
1422
/* taskWasRetained=*/ true );
1403
- unlock (); // we MUST unlock before running the waiting task
1423
+ // we must unlock before running the waiting task,
1424
+ // in order to avoid the potential for the resumed task
1425
+ // to cause a group destroy, in which case the unlock might
1426
+ // attempt memory in an invalid state.
1427
+ unlock ();
1404
1428
return runWaitingTask (preparedWaitingTask);
1405
1429
}
1406
1430
default : {
@@ -1415,7 +1439,11 @@ void DiscardingTaskGroup::offer(AsyncTask *completedTask, AsyncContext *context)
1415
1439
auto prepared = prepareWaitingTaskWithTask (
1416
1440
/* complete=*/ waitingTask, /* with=*/ completedTask,
1417
1441
assumed, /* hadErrorResult=*/ false , alreadyDecrementedStatus);
1418
- unlock (); // we MUST unlock before running the waiting task
1442
+ // we must unlock before running the waiting task,
1443
+ // in order to avoid the potential for the resumed task
1444
+ // to cause a group destroy, in which case the unlock might
1445
+ // attempt memory in an invalid state.
1446
+ unlock ();
1419
1447
return runWaitingTask (prepared);
1420
1448
}
1421
1449
} else {
@@ -1459,7 +1487,7 @@ TaskGroupBase::PreparedWaitingTask TaskGroupBase::prepareWaitingTaskWithTask(
1459
1487
(void ) statusCompletePendingReadyWaiting (assumed);
1460
1488
}
1461
1489
1462
- // Run the task.
1490
+ // Populate the waiting task with value from completedTask .
1463
1491
auto result = PollResult::get (completedTask, hadErrorResult);
1464
1492
SWIFT_TASK_GROUP_DEBUG_LOG (this ,
1465
1493
" resume waiting DONE, task = %p, error:%d, complete with = %p, status = %s" ,
@@ -1759,7 +1787,11 @@ reevaluate_if_taskgroup_has_results:;
1759
1787
waitHead, waitingTask,
1760
1788
/* success*/ std::memory_order_release,
1761
1789
/* failure*/ std::memory_order_acquire)) {
1762
- unlock (); // TODO: remove fragment lock, and use status for synchronization
1790
+ // we must unlock before running the waiting task,
1791
+ // in order to avoid the potential for the resumed task
1792
+ // to cause a group destroy, in which case the unlock might
1793
+ // attempt memory in an invalid state.
1794
+ unlock ();
1763
1795
#if SWIFT_CONCURRENCY_TASK_TO_THREAD_MODEL
1764
1796
// The logic here is paired with the logic in TaskGroupBase::offer. Once
1765
1797
// we run the
0 commit comments