Skip to content

Commit 0ae6c63

Browse files
committed
[Concurrency] Use SchedulerPrivate for the "next waiting task" link.
Reduce the size of AsyncTask by using the first slot of SchedulerPrivate for the next waiting task. Thanks, John!
1 parent 4b92467 commit 0ae6c63

File tree

3 files changed

+22
-12
lines changed

3 files changed

+22
-12
lines changed

include/swift/ABI/Task.h

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,13 @@ class AsyncFunctionPointer {
8888

8989
/// A schedulable job.
9090
class alignas(2 * alignof(void*)) Job {
91+
protected:
92+
// Indices into SchedulerPrivate, for use by the runtime.
93+
enum {
94+
/// The next waiting task link, an AsyncTask that is waiting on a future.
95+
NextWaitingTaskIndex = 0,
96+
};
97+
9198
public:
9299
// Reserved for the use of the scheduler.
93100
void *SchedulerPrivate[2];
@@ -190,16 +197,12 @@ class AsyncTask : public HeapObject, public Job {
190197
/// Reserved for the use of the task-local stack allocator.
191198
void *AllocatorPrivate[4];
192199

193-
/// The next task in the linked list of waiting tasks.
194-
AsyncTask *NextWaitingTask;
195-
196200
AsyncTask(const HeapMetadata *metadata, JobFlags flags,
197201
TaskContinuationFunction *run,
198202
AsyncContext *initialContext)
199203
: HeapObject(metadata), Job(flags, run),
200204
ResumeContext(initialContext),
201-
Status(ActiveTaskStatus()),
202-
NextWaitingTask(nullptr) {
205+
Status(ActiveTaskStatus()) {
203206
assert(flags.isAsyncTask());
204207
}
205208

@@ -265,9 +268,9 @@ class AsyncTask : public HeapObject, public Job {
265268
/// head of the list of tasks.
266269
struct WaitQueueItem {
267270
/// Mask used for the low status bits in a wait queue item.
268-
const uintptr_t statusMask = 0x03;
271+
static const uintptr_t statusMask = 0x03;
269272

270-
uintptr_t storage;
273+
const uintptr_t storage;
271274

272275
Status getStatus() const {
273276
return static_cast<Status>(storage & statusMask);
@@ -359,13 +362,20 @@ class AsyncTask : public HeapObject, public Job {
359362
/// executor.
360363
void completeFuture(AsyncContext *context, ExecutorRef executor);
361364

365+
/// Access the next waiting task, which establishes a singly linked list of
366+
/// tasks that are waiting on a future.
367+
AsyncTask *&getNextWaitingTask() {
368+
return reinterpret_cast<AsyncTask *&>(
369+
SchedulerPrivate[NextWaitingTaskIndex]);
370+
}
371+
362372
static bool classof(const Job *job) {
363373
return job->isAsyncTask();
364374
}
365375
};
366376

367377
// The compiler will eventually assume these.
368-
static_assert(sizeof(AsyncTask) == 14 * sizeof(void*),
378+
static_assert(sizeof(AsyncTask) == 12 * sizeof(void*),
369379
"AsyncTask size is wrong");
370380
static_assert(alignof(AsyncTask) == 2 * alignof(void*),
371381
"AsyncTask alignment is wrong");

stdlib/public/Concurrency/Task.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ FutureFragment::Status AsyncTask::waitFuture(AsyncTask *waitingTask) {
6464
}
6565

6666
// Put the waiting task at the beginning of the wait queue.
67-
waitingTask->NextWaitingTask = queueHead.getTask();
67+
waitingTask->getNextWaitingTask() = queueHead.getTask();
6868
auto newQueueHead = WaitQueueItem::get(Status::Executing, waitingTask);
6969
if (fragment->waitQueue.compare_exchange_weak(
7070
queueHead, newQueueHead, std::memory_order_release,
@@ -119,10 +119,10 @@ void AsyncTask::completeFuture(AsyncContext *context, ExecutorRef executor) {
119119
auto waitingTask = queueHead.getTask();
120120
while (waitingTask) {
121121
// Find the next waiting task.
122-
auto nextWaitingTask = waitingTask->NextWaitingTask;
122+
auto nextWaitingTask = waitingTask->getNextWaitingTask();
123123

124124
// Remove this task from the list.
125-
waitingTask->NextWaitingTask = nullptr;
125+
waitingTask->getNextWaitingTask() = nullptr;
126126

127127
// TODO: schedule this task on the executor rather than running it
128128
// directly.

unittests/runtime/TaskFuture.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ TEST(TaskFutureTest, objectFuture) {
196196
EXPECT_EQ(object, *reinterpret_cast<TestObject **>(waitResult.storage));
197197

198198
// Make sure the object hasn't been destroyed.
199-
EXPECT_EQ(7, objectValueOnComplete);
199+
EXPECT_EQ(size_t(7), objectValueOnComplete);
200200

201201
// Okay, release the task. This should destroy the object.
202202
swift_release(task);

0 commit comments

Comments
 (0)