17
17
#ifndef SWIFT_ABI_TASK_H
18
18
#define SWIFT_ABI_TASK_H
19
19
20
+ #include " swift/Basic/RelativePointer.h"
20
21
#include " swift/ABI/HeapObject.h"
21
22
#include " swift/ABI/MetadataValues.h"
22
23
#include " swift/Runtime/Config.h"
@@ -32,7 +33,21 @@ class TaskStatusRecord;
32
33
33
34
// / An ExecutorRef isn't necessarily just a pointer to an executor
34
35
// / object; it may have other bits set.
35
- using ExecutorRef = Executor *;
36
+ struct ExecutorRef {
37
+ Executor *Pointer;
38
+
39
+ // / Get an executor ref that represents a lack of preference about
40
+ // / where execution resumes. This is only valid in continuations,
41
+ // / return contexts, and so on; it is not generally passed to
42
+ // / executing functions.
43
+ static ExecutorRef noPreference () {
44
+ return { nullptr };
45
+ }
46
+
47
+ bool operator ==(ExecutorRef other) const {
48
+ return Pointer == other.Pointer ;
49
+ }
50
+ };
36
51
37
52
using JobInvokeFunction =
38
53
SWIFT_CC (swift)
@@ -42,6 +57,33 @@ using TaskContinuationFunction =
42
57
SWIFT_CC (swift)
43
58
void (AsyncTask *, ExecutorRef, AsyncContext *);
44
59
60
+ template <class Fn >
61
+ struct AsyncFunctionTypeImpl ;
62
+ template <class Result , class ... Params>
63
+ struct AsyncFunctionTypeImpl <Result(Params...)> {
64
+ // TODO: expand and include the arguments in the parameters.
65
+ using type = TaskContinuationFunction;
66
+ };
67
+
68
+ template <class Fn >
69
+ using AsyncFunctionType = typename AsyncFunctionTypeImpl<Fn>::type;
70
+
71
+ // / A "function pointer" for an async function.
72
+ // /
73
+ // / Eventually, this will always be signed with the data key
74
+ // / using a type-specific discriminator.
75
+ template <class FnType >
76
+ class AsyncFunctionPointer {
77
+ public:
78
+ // / The function to run.
79
+ RelativeDirectPointer<AsyncFunctionType<FnType>,
80
+ /* nullable*/ false ,
81
+ int32_t > Function;
82
+
83
+ // / The expected size of the context.
84
+ uint32_t ExpectedContextSize;
85
+ };
86
+
45
87
// / A schedulable job.
46
88
class alignas (2 * alignof (void *)) Job {
47
89
public:
@@ -76,7 +118,7 @@ class alignas(2 * alignof(void*)) Job {
76
118
}
77
119
78
120
// / Run this job.
79
- void run (Executor * currentExecutor);
121
+ void run (ExecutorRef currentExecutor);
80
122
};
81
123
82
124
// The compiler will eventually assume these.
@@ -128,7 +170,7 @@ class ActiveTaskStatus {
128
170
// / An asynchronous task. Tasks are the analogue of threads for
129
171
// / asynchronous functions: that is, they are a persistent identity
130
172
// / for the overall async computation.
131
- class AsyncTask : public Job {
173
+ class AsyncTask : public HeapObject , public Job {
132
174
public:
133
175
// / The context for resuming the job. When a task is scheduled
134
176
// / as a job, the next continuation should be installed as the
@@ -146,9 +188,10 @@ class AsyncTask : public Job {
146
188
// / Reserved for the use of the task-local stack allocator.
147
189
void *AllocatorPrivate[4 ];
148
190
149
- AsyncTask (JobFlags flags, TaskContinuationFunction *run,
191
+ AsyncTask (const HeapMetadata *metadata, JobFlags flags,
192
+ TaskContinuationFunction *run,
150
193
AsyncContext *initialContext)
151
- : Job(flags, run),
194
+ : HeapObject(metadata), Job(flags, run),
152
195
ResumeContext (initialContext),
153
196
Status(ActiveTaskStatus()) {
154
197
assert (flags.isAsyncTask ());
@@ -164,12 +207,6 @@ class AsyncTask : public Job {
164
207
return Status.load (std::memory_order_relaxed).isCancelled ();
165
208
}
166
209
167
- bool isHeapObject () const { return Flags.task_isHeapObject (); }
168
- HeapObject *heapObjectHeader () {
169
- assert (isHeapObject ());
170
- return reinterpret_cast <HeapObject*>(this ) - 1 ;
171
- }
172
-
173
210
// / A fragment of an async task structure that happens to be a child task.
174
211
class ChildFragment {
175
212
// / The parent task of this task.
@@ -182,6 +219,8 @@ class AsyncTask : public Job {
182
219
AsyncTask *NextChild = nullptr ;
183
220
184
221
public:
222
+ ChildFragment (AsyncTask *parent) : Parent(parent) {}
223
+
185
224
AsyncTask *getParent () const {
186
225
return Parent;
187
226
}
@@ -191,6 +230,8 @@ class AsyncTask : public Job {
191
230
}
192
231
};
193
232
233
+ bool isFuture () const { return Flags.task_isFuture (); }
234
+
194
235
bool hasChildFragment () const { return Flags.task_isChildTask (); }
195
236
ChildFragment *childFragment () {
196
237
assert (hasChildFragment ());
@@ -205,7 +246,7 @@ class AsyncTask : public Job {
205
246
};
206
247
207
248
// The compiler will eventually assume these.
208
- static_assert (sizeof (AsyncTask) == 10 * sizeof(void *),
249
+ static_assert (sizeof (AsyncTask) == 12 * sizeof(void *),
209
250
"AsyncTask size is wrong");
210
251
static_assert (alignof (AsyncTask) == 2 * alignof(void *),
211
252
"AsyncTask alignment is wrong");
@@ -237,6 +278,9 @@ class alignas(MaximumAlignment) AsyncContext {
237
278
TaskContinuationFunction * __ptrauth_swift_async_context_resume
238
279
ResumeParent;
239
280
281
+ // / The executor that the parent needs to be resumed on.
282
+ ExecutorRef ResumeParentExecutor;
283
+
240
284
// / Flags describing this context.
241
285
// /
242
286
// / Note that this field is only 32 bits; any alignment padding
@@ -245,31 +289,44 @@ class alignas(MaximumAlignment) AsyncContext {
245
289
// / is of course interrupted by the YieldToParent field.
246
290
AsyncContextFlags Flags;
247
291
248
- // Fields following this point may not be valid in all instances
249
- // of AsyncContext.
250
-
251
- // / The function to call to temporarily resume running in the
252
- // / parent context temporarily. Generally this means a semantic
253
- // / yield. Requires Flags.hasYieldFunction().
254
- TaskContinuationFunction * __ptrauth_swift_async_context_yield
255
- YieldToParent;
256
-
257
- AsyncContext (AsyncContextFlags flags,
258
- TaskContinuationFunction *resumeParent,
259
- AsyncContext *parent)
260
- : Parent (parent), ResumeParent (resumeParent), Flags (flags) {}
261
-
262
292
AsyncContext (AsyncContextFlags flags,
263
293
TaskContinuationFunction *resumeParent,
264
- TaskContinuationFunction *yieldToParent ,
294
+ ExecutorRef resumeParentExecutor ,
265
295
AsyncContext *parent)
266
- : Parent (parent), ResumeParent (resumeParent), Flags (flags),
267
- YieldToParent (yieldToParent) {}
296
+ : Parent (parent), ResumeParent (resumeParent),
297
+ ResumeParentExecutor (resumeParentExecutor),
298
+ Flags (flags) {}
268
299
269
300
AsyncContext (const AsyncContext &) = delete ;
270
301
AsyncContext &operator =(const AsyncContext &) = delete ;
271
302
};
272
303
304
+ // / An async context that supports yielding.
305
+ class YieldingAsyncContext : public AsyncContext {
306
+ public:
307
+ // / The function to call to temporarily resume running in the
308
+ // / parent context. Generally this means a semantic yield.
309
+ TaskContinuationFunction * __ptrauth_swift_async_context_yield
310
+ YieldToParent;
311
+
312
+ // / The executor that the parent context needs to be yielded to on.
313
+ ExecutorRef YieldToParentExecutor;
314
+
315
+ YieldingAsyncContext (AsyncContextFlags flags,
316
+ TaskContinuationFunction *resumeParent,
317
+ ExecutorRef resumeParentExecutor,
318
+ TaskContinuationFunction *yieldToParent,
319
+ ExecutorRef yieldToParentExecutor,
320
+ AsyncContext *parent)
321
+ : AsyncContext(flags, resumeParent, resumeParentExecutor, parent),
322
+ YieldToParent (yieldToParent),
323
+ YieldToParentExecutor(yieldToParentExecutor) {}
324
+
325
+ static bool classof (const AsyncContext *context) {
326
+ return context->Flags .getKind () == AsyncContextKind::Yielding;
327
+ }
328
+ };
329
+
273
330
} // end namespace swift
274
331
275
332
#endif
0 commit comments