19
19
20
20
#include " swift/Basic/RelativePointer.h"
21
21
#include " swift/ABI/HeapObject.h"
22
+ #include " swift/ABI/Metadata.h"
22
23
#include " swift/ABI/MetadataValues.h"
23
24
#include " swift/Runtime/Config.h"
24
25
#include " swift/Basic/STLExtras.h"
@@ -29,6 +30,7 @@ class AsyncTask;
29
30
class AsyncContext ;
30
31
class Executor ;
31
32
class Job ;
33
+ struct OpaqueValue ;
32
34
class TaskStatusRecord ;
33
35
34
36
// / An ExecutorRef isn't necessarily just a pointer to an executor
@@ -188,12 +190,16 @@ class AsyncTask : public HeapObject, public Job {
188
190
// / Reserved for the use of the task-local stack allocator.
189
191
void *AllocatorPrivate[4 ];
190
192
193
+ // / The next task in the linked list of waiting tasks.
194
+ AsyncTask *NextWaitingTask;
195
+
191
196
AsyncTask (const HeapMetadata *metadata, JobFlags flags,
192
197
TaskContinuationFunction *run,
193
198
AsyncContext *initialContext)
194
199
: HeapObject(metadata), Job(flags, run),
195
200
ResumeContext (initialContext),
196
- Status(ActiveTaskStatus()) {
201
+ Status(ActiveTaskStatus()),
202
+ NextWaitingTask(nullptr ) {
197
203
assert (flags.isAsyncTask ());
198
204
}
199
205
@@ -230,23 +236,117 @@ class AsyncTask : public HeapObject, public Job {
230
236
}
231
237
};
232
238
233
- bool isFuture () const { return Flags.task_isFuture (); }
234
-
235
239
bool hasChildFragment () const { return Flags.task_isChildTask (); }
236
240
ChildFragment *childFragment () {
237
241
assert (hasChildFragment ());
238
242
return reinterpret_cast <ChildFragment*>(this + 1 );
239
243
}
240
244
241
- // TODO: Future fragment
245
+ class FutureFragment {
246
+ public:
247
+ // / Describes the status of the future.
248
+ // /
249
+ // / Futures always being in the "Executing" state, and will always
250
+ // / make a single state change to either Success or Error.
251
+ enum class Status : uintptr_t {
252
+ // / The future is executing or ready to execute. The storage
253
+ // / is not accessible.
254
+ Executing = 0 ,
255
+
256
+ // / The future has completed with result (of type \c resultType).
257
+ Success,
258
+
259
+ // / The future has completed by throwing an error (an \c Error
260
+ // / existential).
261
+ Error,
262
+ };
263
+
264
+ private:
265
+ // / Status of the future.
266
+ std::atomic<Status> status;
267
+
268
+ // / Queue containing all of the tasks that are waiting in `get()`.
269
+ // / FIXME: do we also need a context pointer for each?
270
+ std::atomic<AsyncTask*> waitQueue;
271
+
272
+ // / The type of the result that will be produced by the future.
273
+ const Metadata *resultType;
274
+
275
+ // / The offset of the result in the initial asynchronous context.
276
+ unsigned resultOffset;
277
+
278
+ // / The offset of the error in the initial asynchronous context.
279
+ unsigned errorOffset;
280
+
281
+ // Trailing storage for the result itself. The storage will be uninitialized,
282
+ // contain an instance of \c resultType, or contaon an an \c Error.
283
+
284
+ friend class AsyncTask ;
285
+
286
+ public:
287
+ FutureFragment (
288
+ const Metadata *resultType, size_t resultOffset, size_t errorOffset)
289
+ : status(Status::Success), waitQueue(nullptr ), resultType(resultType),
290
+ resultOffset (resultOffset), errorOffset(errorOffset) { }
291
+
292
+ // / Destroy the storage associated with the future.
293
+ void destroy ();
294
+
295
+ // / Retrieve a pointer to the storage of result.
296
+ OpaqueValue *getStoragePtr () {
297
+ return reinterpret_cast <OpaqueValue *>(
298
+ reinterpret_cast <char *>(this ) + storageOffset (resultType));
299
+ }
300
+
301
+ // / Retrieve a reference to the storage of the
302
+
303
+ // / Compute the offset of the storage from the base of the future
304
+ // / fragment.
305
+ static size_t storageOffset (const Metadata *resultType) {
306
+ size_t offset = sizeof (FutureFragment);
307
+ size_t alignment = resultType->vw_alignment ();
308
+ return (offset + alignment - 1 ) & ~(alignment - 1 );
309
+ }
310
+
311
+ // / Determine the size of the future fragment given a particular future
312
+ // / result type.
313
+ static size_t fragmentSize (const Metadata *resultType);
314
+ };
315
+
316
+ bool isFuture () const { return Flags.task_isFuture (); }
317
+
318
+ FutureFragment *futureFragment () {
319
+ assert (isFuture ());
320
+ if (hasChildFragment ()) {
321
+ return reinterpret_cast <FutureFragment *>(
322
+ reinterpret_cast <ChildFragment*>(this + 1 ) + 1 );
323
+ }
324
+
325
+ return reinterpret_cast <FutureFragment *>(this + 1 );
326
+ }
327
+
328
+ // / Wait for this future to complete.
329
+ // /
330
+ // / \returns the status of the future. If this result is
331
+ // / \c Executing, then \c waitingTask has been added to the
332
+ // / wait queue and will be scheduled when the future completes or
333
+ // / is cancelled. Otherwise, the future has completed and can be
334
+ // / queried.
335
+ FutureFragment::Status waitFuture (AsyncTask *waitingTask);
336
+
337
+ // / Complete this future.
338
+ void completeFuture (AsyncContext *context);
339
+
340
+ // / Schedule waiting tasks now that the future has completed.
341
+ void scheduleWaitingTasks (ExecutorRef executor);
242
342
243
343
static bool classof (const Job *job) {
244
344
return job->isAsyncTask ();
245
345
}
246
346
};
247
347
248
348
// The compiler will eventually assume these.
249
- static_assert (sizeof (AsyncTask) == 12 * sizeof(void *),
349
+ static_assert (sizeof (AsyncTask) == 14 * sizeof(void *),
250
350
"AsyncTask size is wrong");
251
351
static_assert (alignof (AsyncTask) == 2 * alignof(void *),
252
352
"AsyncTask alignment is wrong");
0 commit comments