completeFuture should have acquire-release for the exchange

When a completed task updates the queue head to announce
that it's been completed, it only did an acquire exchange.

By also having it also do a release, we will ensure that
prior writes done by the completed task, before the task is
marked completed, will be correctly ordered as happening
before any subsequent reads by tasks waiting on that
completion status.

Co-authored-by: John McCall <rjmccall@apple.com>
This commit is contained in:
Kavon Farvardin
2023-01-10 16:22:59 -08:00
parent ac10f2a93a
commit ce3da795aa

View File

@@ -114,6 +114,7 @@ FutureFragment::Status AsyncTask::waitFuture(AsyncTask *waitingTask,
assert(isFuture());
auto fragment = futureFragment();
// NOTE: this acquire synchronizes with `completeFuture`.
auto queueHead = fragment->waitQueue.load(std::memory_order_acquire);
bool contextInitialized = false;
auto escalatedPriority = JobPriority::Unspecified;
@@ -214,6 +215,7 @@ FutureFragment::Status AsyncTask::waitFuture(AsyncTask *waitingTask,
continue;
#else
// Put the waiting task at the beginning of the wait queue.
// NOTE: this acquire-release synchronizes with `completeFuture`.
waitingTask->getNextWaitingTask() = queueHead.getTask();
auto newQueueHead = WaitQueueItem::get(Status::Executing, waitingTask);
if (fragment->waitQueue.compare_exchange_weak(
@@ -267,8 +269,10 @@ void AsyncTask::completeFuture(AsyncContext *context) {
hadErrorResult ? Status::Error : Status::Success,
nullptr
);
// NOTE: this acquire-release synchronizes with `waitFuture`.
auto queueHead = fragment->waitQueue.exchange(
newQueueHead, std::memory_order_acquire);
newQueueHead, std::memory_order_acq_rel);
assert(queueHead.getStatus() == Status::Executing);
// If this is task group child, notify the parent group about the completion.