Skip to content

Commit 02cfda9

Browse files
committed
[runtime] swift_task_future_waitImpl: Sink context intialization into slow path
1 parent 3508865 commit 02cfda9

File tree

2 files changed

+46
-31
lines changed

2 files changed

+46
-31
lines changed

include/swift/ABI/Task.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,13 @@ class AsyncTask : public Job {
481481
/// \c Executing, then \c waitingTask has been added to the
482482
/// wait queue and will be scheduled when the future completes. Otherwise,
483483
/// the future has completed and can be queried.
484-
FutureFragment::Status waitFuture(AsyncTask *waitingTask);
484+
/// The waiting task's async context will be intialized with the parameters if
485+
/// the current's task state is executing.
486+
FutureFragment::Status waitFuture(AsyncTask *waitingTask,
487+
AsyncContext *waitingTaskContext,
488+
TaskContinuationFunction *resumeFn,
489+
AsyncContext *callerContext,
490+
OpaqueValue *result);
485491

486492
/// Complete this future.
487493
///

stdlib/public/Concurrency/Task.cpp

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,19 @@ void FutureFragment::destroy() {
5252
}
5353
}
5454

55-
FutureFragment::Status AsyncTask::waitFuture(AsyncTask *waitingTask) {
55+
FutureFragment::Status AsyncTask::waitFuture(AsyncTask *waitingTask,
56+
AsyncContext *waitingTaskContext,
57+
TaskContinuationFunction *resumeFn,
58+
AsyncContext *callerContext,
59+
OpaqueValue *result) {
5660
using Status = FutureFragment::Status;
5761
using WaitQueueItem = FutureFragment::WaitQueueItem;
5862

5963
assert(isFuture());
6064
auto fragment = futureFragment();
6165

6266
auto queueHead = fragment->waitQueue.load(std::memory_order_acquire);
67+
bool contextIntialized = false;
6368
while (true) {
6469
switch (queueHead.getStatus()) {
6570
case Status::Error:
@@ -80,6 +85,16 @@ FutureFragment::Status AsyncTask::waitFuture(AsyncTask *waitingTask) {
8085
break;
8186
}
8287

88+
if (!contextIntialized) {
89+
contextIntialized = true;
90+
auto context =
91+
reinterpret_cast<TaskFutureWaitAsyncContext *>(waitingTaskContext);
92+
context->errorResult = nullptr;
93+
context->successResultPointer = result;
94+
context->ResumeParent = resumeFn;
95+
context->Parent = callerContext;
96+
}
97+
8398
// Put the waiting task at the beginning of the wait queue.
8499
waitingTask->getNextWaitingTask() = queueHead.getTask();
85100
auto newQueueHead = WaitQueueItem::get(Status::Executing, waitingTask);
@@ -687,26 +702,22 @@ static void swift_task_future_waitImpl(
687702
waitingTask->ResumeTask = task_future_wait_resume_adapter;
688703
waitingTask->ResumeContext = callContext;
689704

690-
// Stash the result pointer for when we resume later.
691-
auto context = static_cast<TaskFutureWaitAsyncContext *>(callContext);
692-
context->ResumeParent = resumeFn;
693-
context->Parent = callerContext;
694-
context->successResultPointer = result;
695-
context->errorResult = nullptr;
696-
697705
// Wait on the future.
698706
assert(task->isFuture());
699707

700-
switch (task->waitFuture(waitingTask)) {
708+
switch (task->waitFuture(waitingTask, callContext, resumeFn, callerContext,
709+
result)) {
701710
case FutureFragment::Status::Executing:
702711
// The waiting task has been queued on the future.
703712
return;
704713

705-
case FutureFragment::Status::Success:
714+
case FutureFragment::Status::Success: {
706715
// Run the task with a successful result.
707-
context->fillWithSuccess(task->futureFragment());
708-
// FIXME: force tail call
709-
return waitingTask->runInFullyEstablishedContext();
716+
auto future = task->futureFragment();
717+
future->getResultType()->vw_initializeWithCopy(result,
718+
future->getStoragePtr());
719+
return resumeFn(callerContext);
720+
}
710721

711722
case FutureFragment::Status::Error:
712723
fatalError(0, "future reported an error, but wait cannot throw");
@@ -724,33 +735,31 @@ void swift_task_future_wait_throwingImpl(
724735
waitingTask->ResumeTask = task_wait_throwing_resume_adapter;
725736
waitingTask->ResumeContext = callContext;
726737

727-
// Stash the result pointer for when we resume later.
728-
auto context = static_cast<TaskFutureWaitAsyncContext *>(callContext);
729-
context->ResumeParent =
730-
reinterpret_cast<TaskContinuationFunction *>(resumeFunction);
731-
context->Parent = callerContext;
732-
context->successResultPointer = result;
733-
context->errorResult = nullptr;
738+
auto resumeFn = reinterpret_cast<TaskContinuationFunction *>(resumeFunction);
734739

735740
// Wait on the future.
736741
assert(task->isFuture());
737742

738-
switch (task->waitFuture(waitingTask)) {
743+
switch (task->waitFuture(waitingTask, callContext, resumeFn, callerContext,
744+
result)) {
739745
case FutureFragment::Status::Executing:
740746
// The waiting task has been queued on the future.
741747
return;
742748

743-
case FutureFragment::Status::Success:
744-
// Run the task with a successful result.
745-
context->fillWithSuccess(task->futureFragment());
746-
// FIXME: force tail call
747-
return waitingTask->runInFullyEstablishedContext();
749+
case FutureFragment::Status::Success: {
750+
auto future = task->futureFragment();
751+
future->getResultType()->vw_initializeWithCopy(result,
752+
future->getStoragePtr());
753+
return resumeFunction(callerContext, nullptr /*error*/);
754+
}
748755

749-
case FutureFragment::Status::Error:
756+
case FutureFragment::Status::Error: {
750757
// Run the task with an error result.
751-
context->fillWithError(task->futureFragment());
752-
// FIXME: force tail call
753-
return waitingTask->runInFullyEstablishedContext();
758+
auto future = task->futureFragment();
759+
auto error = future->getError();
760+
swift_errorRetain(error);
761+
return resumeFunction(callerContext, error);
762+
}
754763
}
755764
}
756765

0 commit comments

Comments
 (0)