1919
2020#include " swift/Basic/RelativePointer.h"
2121#include " swift/ABI/HeapObject.h"
22+ #include " swift/ABI/Metadata.h"
2223#include " swift/ABI/MetadataValues.h"
2324#include " swift/Runtime/Config.h"
2425#include " swift/Basic/STLExtras.h"
@@ -29,6 +30,8 @@ class AsyncTask;
2930class AsyncContext ;
3031class Executor ;
3132class Job ;
33+ struct OpaqueValue ;
34+ struct SwiftError ;
3235class TaskStatusRecord ;
3336
3437// / An ExecutorRef isn't necessarily just a pointer to an executor
@@ -86,6 +89,13 @@ class AsyncFunctionPointer {
8689
8790// / A schedulable job.
8891class alignas (2 * alignof (void *)) Job {
92+ protected:
93+ // Indices into SchedulerPrivate, for use by the runtime.
94+ enum {
95+ // / The next waiting task link, an AsyncTask that is waiting on a future.
96+ NextWaitingTaskIndex = 0 ,
97+ };
98+
8999public:
90100 // Reserved for the use of the scheduler.
91101 void *SchedulerPrivate[2 ];
@@ -230,19 +240,142 @@ class AsyncTask : public HeapObject, public Job {
230240 }
231241 };
232242
233- bool isFuture () const { return Flags.task_isFuture (); }
234-
235243 bool hasChildFragment () const { return Flags.task_isChildTask (); }
236244 ChildFragment *childFragment () {
237245 assert (hasChildFragment ());
238246 return reinterpret_cast <ChildFragment*>(this + 1 );
239247 }
240248
241- // TODO: Future fragment
249+ class FutureFragment {
250+ public:
251+ // / Describes the status of the future.
252+ // /
253+ // / Futures always begin in the "Executing" state, and will always
254+ // / make a single state change to either Success or Error.
255+ enum class Status : uintptr_t {
256+ // / The future is executing or ready to execute. The storage
257+ // / is not accessible.
258+ Executing = 0 ,
259+
260+ // / The future has completed with result (of type \c resultType).
261+ Success,
262+
263+ // / The future has completed by throwing an error (an \c Error
264+ // / existential).
265+ Error,
266+ };
267+
268+ // / An item within the wait queue, which includes the status and the
269+ // / head of the list of tasks.
270+ struct WaitQueueItem {
271+ // / Mask used for the low status bits in a wait queue item.
272+ static const uintptr_t statusMask = 0x03 ;
273+
274+ uintptr_t storage;
275+
276+ Status getStatus () const {
277+ return static_cast <Status>(storage & statusMask);
278+ }
279+
280+ AsyncTask *getTask () const {
281+ return reinterpret_cast <AsyncTask *>(storage & ~statusMask);
282+ }
283+
284+ static WaitQueueItem get (Status status, AsyncTask *task) {
285+ return WaitQueueItem{
286+ reinterpret_cast <uintptr_t >(task) | static_cast <uintptr_t >(status)};
287+ }
288+ };
289+
290+ private:
291+ // / Queue containing all of the tasks that are waiting in `get()`.
292+ // /
293+ // / The low bits contain the status, the rest of the pointer is the
294+ // / AsyncTask.
295+ std::atomic<WaitQueueItem> waitQueue;
296+
297+ // / The type of the result that will be produced by the future.
298+ const Metadata *resultType;
299+
300+ // Trailing storage for the result itself. The storage will be uninitialized,
301+ // contain an instance of \c resultType, or contaon an an \c Error.
302+
303+ friend class AsyncTask ;
304+
305+ public:
306+ explicit FutureFragment (const Metadata *resultType)
307+ : waitQueue(WaitQueueItem::get(Status::Executing, nullptr )),
308+ resultType(resultType) { }
309+
310+ // / Destroy the storage associated with the future.
311+ void destroy ();
312+
313+ // / Retrieve a pointer to the storage of result.
314+ OpaqueValue *getStoragePtr () {
315+ return reinterpret_cast <OpaqueValue *>(
316+ reinterpret_cast <char *>(this ) + storageOffset (resultType));
317+ }
318+
319+ // / Retrieve the error.
320+ SwiftError *&getError () {
321+ return *reinterpret_cast <SwiftError **>(
322+ reinterpret_cast <char *>(this ) + storageOffset (resultType));
323+ }
324+
325+ // / Compute the offset of the storage from the base of the future
326+ // / fragment.
327+ static size_t storageOffset (const Metadata *resultType) {
328+ size_t offset = sizeof (FutureFragment);
329+ size_t alignment =
330+ std::max (resultType->vw_alignment (), alignof (SwiftError *));
331+ return (offset + alignment - 1 ) & ~(alignment - 1 );
332+ }
333+
334+ // / Determine the size of the future fragment given a particular future
335+ // / result type.
336+ static size_t fragmentSize (const Metadata *resultType) {
337+ return storageOffset (resultType) +
338+ std::max (resultType->vw_size (), sizeof (SwiftError *));
339+ }
340+ };
341+
342+ bool isFuture () const { return Flags.task_isFuture (); }
343+
344+ FutureFragment *futureFragment () {
345+ assert (isFuture ());
346+ if (hasChildFragment ()) {
347+ return reinterpret_cast <FutureFragment *>(
348+ reinterpret_cast <ChildFragment*>(this + 1 ) + 1 );
349+ }
350+
351+ return reinterpret_cast <FutureFragment *>(this + 1 );
352+ }
353+
354+ // / Wait for this future to complete.
355+ // /
356+ // / \returns the status of the future. If this result is
357+ // / \c Executing, then \c waitingTask has been added to the
358+ // / wait queue and will be scheduled when the future completes. Otherwise,
359+ // / the future has completed and can be queried.
360+ FutureFragment::Status waitFuture (AsyncTask *waitingTask);
361+
362+ // / Complete this future.
363+ // /
364+ // / Upon completion, any waiting tasks will be scheduled on the given
365+ // / executor.
366+ void completeFuture (AsyncContext *context, ExecutorRef executor);
242367
243368 static bool classof (const Job *job) {
244369 return job->isAsyncTask ();
245370 }
371+
372+ private:
373+ // / Access the next waiting task, which establishes a singly linked list of
374+ // / tasks that are waiting on a future.
375+ AsyncTask *&getNextWaitingTask () {
376+ return reinterpret_cast <AsyncTask *&>(
377+ SchedulerPrivate[NextWaitingTaskIndex]);
378+ }
246379};
247380
248381// The compiler will eventually assume these.
@@ -327,6 +460,20 @@ class YieldingAsyncContext : public AsyncContext {
327460 }
328461};
329462
463+ // / An asynchronous context within a task that describes a general "Future".
464+ // / task.
465+ // /
466+ // / This type matches the ABI of a function `<T> () async throws -> T`, which
467+ // / is the type used by `Task.runDetached` and `Task.group.add` to create
468+ // / futures.
469+ class FutureAsyncContext : public AsyncContext {
470+ public:
471+ SwiftError *errorResult = nullptr ;
472+ OpaqueValue *indirectResult;
473+
474+ using AsyncContext::AsyncContext;
475+ };
476+
330477} // end namespace swift
331478
332479#endif
0 commit comments