Skip to content

Commit 039403c

Browse files
authored
Merge pull request #41165 from Catfish-Man/linked-lost
Fix SR-15785 by adding a cached reference to the last linked list node, avoiding n^2 append scaling
2 parents 4b8ba3c + 1707ffe commit 039403c

File tree

1 file changed

+20
-20
lines changed

1 file changed

+20
-20
lines changed

include/swift/ABI/TaskStatus.h

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -164,14 +164,21 @@ class ChildTaskStatusRecord : public TaskStatusRecord {
164164
/// and are only tracked by their respective `TaskGroupTaskStatusRecord`.
165165
class TaskGroupTaskStatusRecord : public TaskStatusRecord {
166166
AsyncTask *FirstChild;
167+
AsyncTask *LastChild;
167168

168169
public:
169170
TaskGroupTaskStatusRecord()
170-
: TaskStatusRecord(TaskStatusRecordKind::TaskGroup), FirstChild(nullptr) {
171+
: TaskStatusRecord(TaskStatusRecordKind::TaskGroup),
172+
FirstChild(nullptr),
173+
LastChild(nullptr) {
171174
}
172175

173176
TaskGroupTaskStatusRecord(AsyncTask *child)
174-
: TaskStatusRecord(TaskStatusRecordKind::TaskGroup), FirstChild(child) {}
177+
: TaskStatusRecord(TaskStatusRecordKind::TaskGroup),
178+
FirstChild(child),
179+
LastChild(child) {
180+
assert(!LastChild || !LastChild->childFragment()->getNextChild());
181+
}
175182

176183
TaskGroup *getGroup() { return reinterpret_cast<TaskGroup *>(this); }
177184

@@ -185,38 +192,28 @@ class TaskGroupTaskStatusRecord : public TaskStatusRecord {
185192
assert(child->hasGroupChildFragment());
186193
assert(child->groupChildFragment()->getGroup() == getGroup());
187194

195+
auto oldLastChild = LastChild;
196+
LastChild = child;
197+
188198
if (!FirstChild) {
189199
// This is the first child we ever attach, so store it as FirstChild.
190200
FirstChild = child;
191201
return;
192202
}
193203

194-
// We need to traverse the siblings to find the last one and add the child
195-
// there.
196-
// FIXME: just set prepend to the current head, no need to traverse.
197-
198-
auto cur = FirstChild;
199-
while (cur) {
200-
// no need to check hasChildFragment, all tasks we store here have them.
201-
auto fragment = cur->childFragment();
202-
if (auto next = fragment->getNextChild()) {
203-
cur = next;
204-
} else {
205-
// we're done searching and `cur` is the last
206-
break;
207-
}
208-
}
209-
210-
cur->childFragment()->setNextChild(child);
204+
oldLastChild->childFragment()->setNextChild(child);
211205
}
212206

213207
void detachChild(AsyncTask *child) {
214208
assert(child && "cannot remove a null child from group");
215209
if (FirstChild == child) {
216210
FirstChild = getNextChildTask(child);
211+
if (FirstChild == nullptr) {
212+
LastChild = nullptr;
213+
}
217214
return;
218215
}
219-
216+
220217
AsyncTask *prev = FirstChild;
221218
// Remove the child from the linked list, i.e.:
222219
// prev -> afterPrev -> afterChild
@@ -230,6 +227,9 @@ class TaskGroupTaskStatusRecord : public TaskStatusRecord {
230227
if (afterPrev == child) {
231228
auto afterChild = getNextChildTask(child);
232229
prev->childFragment()->setNextChild(afterChild);
230+
if (child == LastChild) {
231+
LastChild = prev;
232+
}
233233
return;
234234
}
235235

0 commit comments

Comments
 (0)