Skip to content

Commit 9fecd4b

Browse files
committed
[DiscardingTaskGroup] Properly detach when LAST task is failed, and prior failure was already stored
1 parent 683f003 commit 9fecd4b

File tree

1 file changed

+18
-5
lines changed

1 file changed

+18
-5
lines changed

stdlib/public/Concurrency/TaskGroup.cpp

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
using namespace swift;
6666

6767
#if 0
68+
#define SWIFT_TASK_GROUP_DEBUG_LOG_ENABLED 1
6869
#define SWIFT_TASK_GROUP_DEBUG_LOG(group, fmt, ...) \
6970
fprintf(stderr, "[%#lx] [%s:%d][group(%p%s)] (%s) " fmt "\n", \
7071
(unsigned long)Thread::current().platformThreadId(), \
@@ -81,6 +82,7 @@ fprintf(stderr, "[%#lx] [%s:%d][group(%p)] (%s) " fmt "\n", \
8182
__FUNCTION__, \
8283
__VA_ARGS__)
8384
#else
85+
#define SWIFT_TASK_GROUP_DEBUG_LOG_ENABLED 0
8486
#define SWIFT_TASK_GROUP_DEBUG_LOG(group, fmt, ...) (void)0
8587
#define SWIFT_TASK_GROUP_DEBUG_LOG_0(group, fmt, ...) (void)0
8688
#endif
@@ -941,7 +943,7 @@ static void swift_taskGroup_initializeWithFlagsImpl(size_t rawGroupFlags,
941943
// ==== child task management --------------------------------------------------
942944

943945
void TaskGroup::addChildTask(AsyncTask *child) {
944-
SWIFT_TASK_DEBUG_LOG("attach child task = %p to group = %p", child, this);
946+
SWIFT_TASK_GROUP_DEBUG_LOG(this, "attach child task = %p", child);
945947

946948
// Add the child task to this task group. The corresponding removal
947949
// won't happen until the parent task successfully polls for this child
@@ -959,7 +961,7 @@ void TaskGroup::addChildTask(AsyncTask *child) {
959961
}
960962

961963
void TaskGroup::removeChildTask(AsyncTask *child) {
962-
SWIFT_TASK_DEBUG_LOG("detach child task = %p from group = %p", child, this);
964+
SWIFT_TASK_GROUP_DEBUG_LOG(this, "detach child task = %p", child);
963965

964966
auto groupRecord = asBaseImpl(this)->getTaskRecord();
965967

@@ -979,7 +981,7 @@ static void swift_taskGroup_destroyImpl(TaskGroup *group) {
979981
}
980982

981983
void AccumulatingTaskGroup::destroy() {
982-
#if SWIFT_TASK_DEBUG_LOG_ENABLED
984+
#if SWIFT_TASK_GROUP_DEBUG_LOG_ENABLED
983985
if (!this->isEmpty()) {
984986
auto status = this->statusLoadRelaxed();
985987
SWIFT_TASK_GROUP_DEBUG_LOG(this, "destroy, tasks .ready = %d, .pending = %llu",
@@ -988,7 +990,10 @@ void AccumulatingTaskGroup::destroy() {
988990
SWIFT_TASK_DEBUG_LOG("destroying task group = %p", this);
989991
}
990992
#endif
993+
// Verify using the group's status that indeed we're expected to be empty
991994
assert(this->isEmpty() && "Attempted to destroy non-empty task group!");
995+
// Double check by inspecting the group record, it should contain no children
996+
assert(getTaskRecord()->getFirstChild() == nullptr && "Task group record still has child task!");
992997

993998
// First, remove the group from the task and deallocate the record
994999
removeStatusRecordFromSelf(getTaskRecord());
@@ -1002,7 +1007,7 @@ void AccumulatingTaskGroup::destroy() {
10021007
}
10031008

10041009
void DiscardingTaskGroup::destroy() {
1005-
#if SWIFT_TASK_DEBUG_LOG_ENABLED
1010+
#if SWIFT_TASK_GROUP_DEBUG_LOG_ENABLED
10061011
if (!this->isEmpty()) {
10071012
auto status = this->statusLoadRelaxed();
10081013
SWIFT_TASK_GROUP_DEBUG_LOG(this, "destroy, tasks .ready = %d, .pending = %llu",
@@ -1011,7 +1016,10 @@ void DiscardingTaskGroup::destroy() {
10111016
SWIFT_TASK_DEBUG_LOG("destroying discarding task group = %p", this);
10121017
}
10131018
#endif
1019+
// Verify using the group's status that indeed we're expected to be empty
10141020
assert(this->isEmpty() && "Attempted to destroy non-empty task group!");
1021+
// Double check by inspecting the group record, it should contain no children
1022+
assert(getTaskRecord()->getFirstChild() == nullptr && "Task group record still has child task!");
10151023

10161024
// First, remove the group from the task and deallocate the record
10171025
removeStatusRecordFromSelf(getTaskRecord());
@@ -1249,7 +1257,12 @@ void DiscardingTaskGroup::offer(AsyncTask *completedTask, AsyncContext *context)
12491257
alreadyDecrementedStatus);
12501258
break;
12511259
case ReadyStatus::Error:
1252-
SWIFT_TASK_GROUP_DEBUG_LOG(this, "offer, complete, resume with errorItem.task:%p", readyErrorItem.getTask());
1260+
// The completed task failed, but we already stored a different failed task.
1261+
// Thus we discard this error and complete with the previously stored.
1262+
SWIFT_TASK_GROUP_DEBUG_LOG(this, "offer, complete, discard error completedTask %p, resume with errorItem.task:%p",
1263+
completedTask,
1264+
readyErrorItem.getTask());
1265+
_swift_taskGroup_detachChild(asAbstract(this), completedTask);
12531266
resumeWaitingTask(readyErrorItem.getTask(), assumed,
12541267
/*hadErrorResult=*/true,
12551268
alreadyDecrementedStatus,

0 commit comments

Comments
 (0)