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,8 @@ class AsyncTask;
29
30
class AsyncContext ;
30
31
class Executor ;
31
32
class Job ;
33
+ struct OpaqueValue ;
34
+ struct SwiftError ;
32
35
class TaskStatusRecord ;
33
36
34
37
// / An ExecutorRef isn't necessarily just a pointer to an executor
@@ -86,6 +89,13 @@ class AsyncFunctionPointer {
86
89
87
90
// / A schedulable job.
88
91
class 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
+
89
99
public:
90
100
// Reserved for the use of the scheduler.
91
101
void *SchedulerPrivate[2 ];
@@ -230,19 +240,142 @@ class AsyncTask : public HeapObject, public Job {
230
240
}
231
241
};
232
242
233
- bool isFuture () const { return Flags.task_isFuture (); }
234
-
235
243
bool hasChildFragment () const { return Flags.task_isChildTask (); }
236
244
ChildFragment *childFragment () {
237
245
assert (hasChildFragment ());
238
246
return reinterpret_cast <ChildFragment*>(this + 1 );
239
247
}
240
248
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);
242
367
243
368
static bool classof (const Job *job) {
244
369
return job->isAsyncTask ();
245
370
}
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
+ }
246
379
};
247
380
248
381
// The compiler will eventually assume these.
@@ -327,6 +460,20 @@ class YieldingAsyncContext : public AsyncContext {
327
460
}
328
461
};
329
462
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
+
330
477
} // end namespace swift
331
478
332
479
#endif
0 commit comments