@@ -28,7 +28,8 @@ size_t FutureFragment::fragmentSize(const Metadata *resultType) {
28
28
}
29
29
30
30
void FutureFragment::destroy () {
31
- switch (status.load ()) {
31
+ auto queueHead = waitQueue.load (std::memory_order_acquire);
32
+ switch (queueHead.getStatus ()) {
32
33
case Status::Executing:
33
34
assert (false && " destroying a task that never completed" );
34
35
@@ -43,41 +44,49 @@ void FutureFragment::destroy() {
43
44
}
44
45
45
46
FutureFragment::Status AsyncTask::waitFuture (AsyncTask *waitingTask) {
47
+ using Status = FutureFragment::Status;
48
+ using WaitQueueItem = FutureFragment::WaitQueueItem;
49
+
46
50
assert (isFuture ());
47
51
auto fragment = futureFragment ();
48
52
49
- auto currentStatus = fragment->status .load ();
50
- switch (currentStatus) {
51
- case FutureFragment::Status::Error:
52
- case FutureFragment::Status::Success:
53
- // The task is done; we don't need to wait.
54
- return currentStatus;
55
-
56
- case FutureFragment::Status::Executing:
57
- break ;
58
- }
59
-
60
- // Put the waiting task at the beginning of the wait queue.
53
+ auto queueHead = fragment->waitQueue .load (std::memory_order_acquire);
61
54
while (true ) {
62
- waitingTask->NextWaitingTask = fragment->waitQueue .load ();
63
- if (fragment->waitQueue .compare_exchange_strong (
64
- waitingTask->NextWaitingTask , waitingTask)) {
55
+ switch (queueHead.getStatus ()) {
56
+ case Status::Error:
57
+ case Status::Success:
58
+ // The task is done; we don't need to wait.
59
+ return queueHead.getStatus ();
60
+
61
+ case Status::Executing:
62
+ // Task is now complete. We'll need to add ourselves to the queue.
63
+ break ;
64
+ }
65
+
66
+ // Put the waiting task at the beginning of the wait queue.
67
+ waitingTask->NextWaitingTask = queueHead.getTask ();
68
+ auto newQueueHead = WaitQueueItem::get (Status::Executing, waitingTask);
69
+ if (fragment->waitQueue .compare_exchange_weak (
70
+ queueHead, newQueueHead, std::memory_order_release,
71
+ std::memory_order_acquire)) {
65
72
// Escalate the priority of this task based on the priority
66
73
// of the waiting task.
67
74
swift_task_escalate (this , waitingTask->Flags .getPriority ());
68
- break ;
75
+ return FutureFragment::Status::Executing ;
69
76
}
70
77
}
71
-
72
- return FutureFragment::Status::Executing;
73
78
}
74
79
75
- void AsyncTask::completeFuture (AsyncContext *context) {
80
+ void AsyncTask::completeFuture (AsyncContext *context, ExecutorRef executor) {
81
+ using Status = FutureFragment::Status;
82
+ using WaitQueueItem = FutureFragment::WaitQueueItem;
83
+
76
84
assert (isFuture ());
77
85
auto fragment = futureFragment ();
78
86
auto storagePtr = fragment->getStoragePtr ();
79
87
80
88
// Check for an error.
89
+ bool hadErrorResult = false ;
81
90
if (unsigned errorOffset = fragment->errorOffset ) {
82
91
// Find the error object in the context.
83
92
auto errorPtrPtr = reinterpret_cast <char *>(context) + errorOffset;
@@ -86,42 +95,42 @@ void AsyncTask::completeFuture(AsyncContext *context) {
86
95
// If there is an error, take it and we're done.
87
96
if (errorObject) {
88
97
*reinterpret_cast <OpaqueValue **>(storagePtr) = errorObject;
89
- fragment->status = FutureFragment::Status::Error;
90
- return ;
98
+ hadErrorResult = true ;
91
99
}
92
100
}
93
101
94
- // Take the success value.
95
- auto resultPtr = reinterpret_cast <OpaqueValue *>(
96
- reinterpret_cast <char *>(context) + fragment->resultOffset );
97
- fragment->resultType ->vw_initializeWithTake (storagePtr, resultPtr);
98
- fragment->status = FutureFragment::Status::Success;
99
- }
100
-
101
- void AsyncTask::scheduleWaitingTasks (ExecutorRef executor) {
102
- assert (isFuture ());
103
- auto fragment = futureFragment ();
104
-
105
- auto waitingTask = fragment->waitQueue .load ();
106
-
107
- // Unnecessary, but useful for the assertion at the end.
108
- fragment->waitQueue = nullptr ;
102
+ if (!hadErrorResult) {
103
+ // Take the success value.
104
+ auto resultPtr = reinterpret_cast <OpaqueValue *>(
105
+ reinterpret_cast <char *>(context) + fragment->resultOffset );
106
+ fragment->resultType ->vw_initializeWithTake (storagePtr, resultPtr);
107
+ }
109
108
109
+ // Update the status to signal completion.
110
+ auto newQueueHead = WaitQueueItem::get (
111
+ hadErrorResult ? Status::Error : Status::Success,
112
+ nullptr
113
+ );
114
+ auto queueHead = fragment->waitQueue .exchange (
115
+ newQueueHead, std::memory_order_acquire);
116
+ assert (queueHead.getStatus () == Status::Executing);
117
+
118
+ // Notify every
119
+ auto waitingTask = queueHead.getTask ();
110
120
while (waitingTask) {
111
121
// Find the next waiting task.
112
122
auto nextWaitingTask = waitingTask->NextWaitingTask ;
113
123
114
124
// Remove this task from the list.
115
125
waitingTask->NextWaitingTask = nullptr ;
116
126
117
- // TODO: schedule this task on the executor.
127
+ // TODO: schedule this task on the executor rather than running it
128
+ // directly.
129
+ waitingTask->run (executor);
118
130
119
131
// Move to the next task.
120
132
waitingTask = nextWaitingTask;
121
133
}
122
-
123
- // Nobody should be able to add anything to the queue in this function.
124
- assert (!fragment->waitQueue .load ());
125
134
}
126
135
127
136
SWIFT_CC (swift)
@@ -171,12 +180,9 @@ static void completeTask(AsyncTask *task, ExecutorRef executor,
171
180
// to wait for the object to be destroyed.
172
181
_swift_task_alloc_destroy (task);
173
182
183
+ // Complete the future.
174
184
if (task->isFuture ()) {
175
- // Complete the future, taking the result from the context.
176
- task->completeFuture (context);
177
-
178
- // Schedule tasks that are waiting on the future.
179
- task->scheduleWaitingTasks (executor);
185
+ task->completeFuture (context, executor);
180
186
}
181
187
182
188
// TODO: set something in the status?
0 commit comments