Skip to content

Commit 0b8e716

Browse files
committed
swift_task_future_waitImpl: Sink context intialization into slow path
1 parent 10e3d2e commit 0b8e716

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
@@ -53,14 +53,19 @@ void FutureFragment::destroy() {
5353
}
5454
}
5555

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

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

6367
auto queueHead = fragment->waitQueue.load(std::memory_order_acquire);
68+
bool contextIntialized = false;
6469
while (true) {
6570
switch (queueHead.getStatus()) {
6671
case Status::Error:
@@ -83,6 +88,16 @@ FutureFragment::Status AsyncTask::waitFuture(AsyncTask *waitingTask) {
8388
break;
8489
}
8590

91+
if (!contextIntialized) {
92+
contextIntialized = true;
93+
auto context =
94+
reinterpret_cast<TaskFutureWaitAsyncContext *>(waitingTaskContext);
95+
context->errorResult = nullptr;
96+
context->successResultPointer = result;
97+
context->ResumeParent = resumeFn;
98+
context->Parent = callerContext;
99+
}
100+
86101
// Put the waiting task at the beginning of the wait queue.
87102
waitingTask->getNextWaitingTask() = queueHead.getTask();
88103
auto newQueueHead = WaitQueueItem::get(Status::Executing, waitingTask);
@@ -693,26 +708,22 @@ static void swift_task_future_waitImpl(
693708
waitingTask->ResumeTask = task_future_wait_resume_adapter;
694709
waitingTask->ResumeContext = callContext;
695710

696-
// Stash the result pointer for when we resume later.
697-
auto context = static_cast<TaskFutureWaitAsyncContext *>(callContext);
698-
context->ResumeParent = resumeFn;
699-
context->Parent = callerContext;
700-
context->successResultPointer = result;
701-
context->errorResult = nullptr;
702-
703711
// Wait on the future.
704712
assert(task->isFuture());
705713

706-
switch (task->waitFuture(waitingTask)) {
714+
switch (task->waitFuture(waitingTask, callContext, resumeFn, callerContext,
715+
result)) {
707716
case FutureFragment::Status::Executing:
708717
// The waiting task has been queued on the future.
709718
return;
710719

711-
case FutureFragment::Status::Success:
720+
case FutureFragment::Status::Success: {
712721
// Run the task with a successful result.
713-
context->fillWithSuccess(task->futureFragment());
714-
// FIXME: force tail call
715-
return waitingTask->runInFullyEstablishedContext();
722+
auto future = task->futureFragment();
723+
future->getResultType()->vw_initializeWithCopy(result,
724+
future->getStoragePtr());
725+
return resumeFn(callerContext);
726+
}
716727

717728
case FutureFragment::Status::Error:
718729
swift_Concurrency_fatalError(0, "future reported an error, but wait cannot throw");
@@ -730,33 +741,31 @@ void swift_task_future_wait_throwingImpl(
730741
waitingTask->ResumeTask = task_wait_throwing_resume_adapter;
731742
waitingTask->ResumeContext = callContext;
732743

733-
// Stash the result pointer for when we resume later.
734-
auto context = static_cast<TaskFutureWaitAsyncContext *>(callContext);
735-
context->ResumeParent =
736-
reinterpret_cast<TaskContinuationFunction *>(resumeFunction);
737-
context->Parent = callerContext;
738-
context->successResultPointer = result;
739-
context->errorResult = nullptr;
744+
auto resumeFn = reinterpret_cast<TaskContinuationFunction *>(resumeFunction);
740745

741746
// Wait on the future.
742747
assert(task->isFuture());
743748

744-
switch (task->waitFuture(waitingTask)) {
749+
switch (task->waitFuture(waitingTask, callContext, resumeFn, callerContext,
750+
result)) {
745751
case FutureFragment::Status::Executing:
746752
// The waiting task has been queued on the future.
747753
return;
748754

749-
case FutureFragment::Status::Success:
750-
// Run the task with a successful result.
751-
context->fillWithSuccess(task->futureFragment());
752-
// FIXME: force tail call
753-
return waitingTask->runInFullyEstablishedContext();
755+
case FutureFragment::Status::Success: {
756+
auto future = task->futureFragment();
757+
future->getResultType()->vw_initializeWithCopy(result,
758+
future->getStoragePtr());
759+
return resumeFunction(callerContext, nullptr /*error*/);
760+
}
754761

755-
case FutureFragment::Status::Error:
762+
case FutureFragment::Status::Error: {
756763
// Run the task with an error result.
757-
context->fillWithError(task->futureFragment());
758-
// FIXME: force tail call
759-
return waitingTask->runInFullyEstablishedContext();
764+
auto future = task->futureFragment();
765+
auto error = future->getError();
766+
swift_errorRetain(error);
767+
return resumeFunction(callerContext, error);
768+
}
760769
}
761770
}
762771

0 commit comments

Comments
 (0)