Skip to content

Commit 80af928

Browse files
authored
Merge pull request #40554 from apple/rokhinip/synchronize-group-child-creation-and-cancellation-5.6
5.6 [Concurrency]: Synchronize adding a child task to a TaskGroup with parent task
2 parents 5f5def7 + c3e6d71 commit 80af928

File tree

4 files changed

+27
-5
lines changed

4 files changed

+27
-5
lines changed

include/swift/ABI/TaskGroup.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ class alignas(Alignment_TaskGroup) TaskGroup {
4242

4343
/// Checks the cancellation status of the group.
4444
bool isCancelled();
45+
46+
// Add a child task to the group. Always called with the status record lock of
47+
// the parent task held
48+
void addChildTask(AsyncTask *task);
4549
};
4650

4751
} // end namespace swift

stdlib/public/CompatibilityOverride/CompatibilityOverrideConcurrency.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ OVERRIDE_TASK_GROUP(taskGroup_initialize, void,
241241
SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift),
242242
swift::, (TaskGroup *group, const Metadata *T), (group, T))
243243

244-
OVERRIDE_TASK_GROUP(taskGroup_attachChild, void,
244+
OVERRIDE_TASK_STATUS(taskGroup_attachChild, void,
245245
SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift),
246246
swift::, (TaskGroup *group, AsyncTask *child),
247247
(group, child))

stdlib/public/Concurrency/TaskGroup.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -472,15 +472,13 @@ static void swift_taskGroup_initializeImpl(TaskGroup *group, const Metadata *T)
472472
// =============================================================================
473473
// ==== add / attachChild ------------------------------------------------------
474474

475-
SWIFT_CC(swift)
476-
static void swift_taskGroup_attachChildImpl(TaskGroup *group,
477-
AsyncTask *child) {
475+
void TaskGroup::addChildTask(AsyncTask *child) {
478476
SWIFT_TASK_DEBUG_LOG("attach child task = %p to group = %p", child, group);
479477

480478
// The counterpart of this (detachChild) is performed by the group itself,
481479
// when it offers the completed (child) task's value to a waiting task -
482480
// during the implementation of `await group.next()`.
483-
auto groupRecord = asImpl(group)->getTaskRecord();
481+
auto groupRecord = asImpl(this)->getTaskRecord();
484482
groupRecord->attachChild(child);
485483
}
486484

stdlib/public/Concurrency/TaskStatus.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,26 @@ swift_task_detachChildImpl(ChildTaskStatusRecord *record) {
468468
swift_task_removeStatusRecord(record);
469469
}
470470

471+
SWIFT_CC(swift)
472+
static void swift_taskGroup_attachChildImpl(TaskGroup *group,
473+
AsyncTask *child) {
474+
475+
// We are always called from the context of the parent
476+
//
477+
// Acquire the status record lock of parent - we want to synchronize with
478+
// concurrent cancellation or escalation as we're adding new tasks to the
479+
// group.
480+
481+
Optional<StatusRecordLockRecord> recordLockRecord;
482+
auto parent = swift_task_getCurrent();
483+
auto oldStatus =
484+
acquireStatusRecordLock(parent, recordLockRecord, LockContext::OnTask);
485+
group->addChildTask(child);
486+
487+
// Release the status record lock, restoring exactly the old status.
488+
releaseStatusRecordLock(parent, oldStatus, recordLockRecord);
489+
}
490+
471491
/****************************** CANCELLATION ******************************/
472492
/**************************************************************************/
473493

0 commit comments

Comments
 (0)