Skip to content

Commit df577f2

Browse files
committed
Fix SR-15785 by adding a cached reference to the last linked list node, avoiding n^2 append scaling
1 parent 64bc16a commit df577f2

File tree

1 file changed

+18
-20
lines changed

1 file changed

+18
-20
lines changed

include/swift/ABI/TaskStatus.h

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -164,14 +164,19 @@ 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) {}
175180

176181
TaskGroup *getGroup() { return reinterpret_cast<TaskGroup *>(this); }
177182

@@ -185,38 +190,28 @@ class TaskGroupTaskStatusRecord : public TaskStatusRecord {
185190
assert(child->hasGroupChildFragment());
186191
assert(child->groupChildFragment()->getGroup() == getGroup());
187192

193+
auto oldLastChild = LastChild;
194+
LastChild = child;
195+
188196
if (!FirstChild) {
189197
// This is the first child we ever attach, so store it as FirstChild.
190198
FirstChild = child;
191199
return;
192200
}
193201

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);
202+
oldLastChild->childFragment()->setNextChild(child);
211203
}
212204

213205
void detachChild(AsyncTask *child) {
214206
assert(child && "cannot remove a null child from group");
215207
if (FirstChild == child) {
216208
FirstChild = getNextChildTask(child);
209+
if (FirstChild == nullptr) {
210+
LastChild = nullptr;
211+
}
217212
return;
218213
}
219-
214+
220215
AsyncTask *prev = FirstChild;
221216
// Remove the child from the linked list, i.e.:
222217
// prev -> afterPrev -> afterChild
@@ -230,6 +225,9 @@ class TaskGroupTaskStatusRecord : public TaskStatusRecord {
230225
if (afterPrev == child) {
231226
auto afterChild = getNextChildTask(child);
232227
prev->childFragment()->setNextChild(afterChild);
228+
if (child == LastChild) {
229+
LastChild = prev;
230+
}
233231
return;
234232
}
235233

0 commit comments

Comments
 (0)