Skip to content

Commit 35a42ef

Browse files
committed
[Concurrency] Store child record when async let child task spawned
1 parent 282cbc3 commit 35a42ef

38 files changed

+1031
-113
lines changed

include/swift/ABI/AsyncLet.h

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//===--- TaskGroup.h - ABI structures for task groups -00--------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// Swift ABI describing task groups.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_ABI_TASK_ASYNC_LET_H
18+
#define SWIFT_ABI_TASK_ASYNC_LET_H
19+
20+
#include "swift/ABI/Task.h"
21+
#include "swift/ABI/HeapObject.h"
22+
#include "swift/Runtime/Concurrency.h"
23+
#include "swift/Runtime/Config.h"
24+
#include "swift/Basic/RelativePointer.h"
25+
#include "swift/Basic/STLExtras.h"
26+
27+
namespace swift {
28+
29+
/// Represents an in-flight `async let`, i.e. the Task that is computing the
30+
/// result of the async let, along with the awaited status and other metadata.
31+
class alignas(Alignment_AsyncLet) AsyncLet {
32+
public:
33+
// These constructors do not initialize the AsyncLet instance, and the
34+
// destructor does not destroy the AsyncLet instance; you must call
35+
// swift_asyncLet_{initialize,destroy} yourself.
36+
constexpr AsyncLet()
37+
: PrivateData{} {}
38+
39+
// TODO: not sure how many words we should reserve
40+
void *PrivateData[NumWords_AsyncLet];
41+
42+
/// Returns true if the `async let` was already awaited on at-least once.
43+
bool wasAwaitedOn() const;
44+
45+
/// Returns the child task that is associated with this async let.
46+
/// The tasks completion is used to fulfil the value represented by this async let.
47+
AsyncTask *getTask() const;
48+
49+
};
50+
51+
} // end namespace swift
52+
53+
#endif // SWIFT_ABI_TASK_ASYNC_LET_H

include/swift/ABI/MetadataValues.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ enum {
4949

5050
/// The number of words in a task group.
5151
NumWords_TaskGroup = 32,
52+
53+
/// The number of words in an AsyncLet (flags + task pointer)
54+
NumWords_AsyncLet = 8, // TODO: not sure how much is enough, these likely could be pretty small
5255
};
5356

5457
struct InProcess;
@@ -127,6 +130,9 @@ const size_t Alignment_DefaultActor = MaximumAlignment;
127130
/// The alignment of a TaskGroup.
128131
const size_t Alignment_TaskGroup = MaximumAlignment;
129132

133+
/// The alignment of an AsyncLet.
134+
const size_t Alignment_AsyncLet = MaximumAlignment;
135+
130136
/// Flags stored in the value-witness table.
131137
template <typename int_type>
132138
class TargetValueWitnessFlags {

include/swift/ABI/TaskGroup.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ namespace swift {
2929
/// The task group is responsible for maintaining dynamically created child tasks.
3030
class alignas(Alignment_TaskGroup) TaskGroup {
3131
public:
32-
// These constructors do not initialize the actor instance, and the
33-
// destructor does not destroy the actor instance; you must call
32+
// These constructors do not initialize the group instance, and the
33+
// destructor does not destroy the group instance; you must call
3434
// swift_taskGroup_{initialize,destroy} yourself.
3535
constexpr TaskGroup()
3636
: PrivateData{} {}
@@ -43,4 +43,4 @@ class alignas(Alignment_TaskGroup) TaskGroup {
4343

4444
} // end namespace swift
4545

46-
#endif
46+
#endif // SWIFT_ABI_TASK_GROUP_H

include/swift/AST/Builtins.def

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -782,6 +782,14 @@ BUILTIN_MISC_OPERATION_WITH_SILGEN(GetCurrentAsyncTask, "getCurrentAsyncTask", "
782782
/// Cancel the given asynchronous task.
783783
BUILTIN_MISC_OPERATION_WITH_SILGEN(CancelAsyncTask, "cancelAsyncTask", "", Special)
784784

785+
/// createAsyncLet(): (
786+
/// Int, @escaping () async throws -> T
787+
/// ) -> Builtin.RawPointer
788+
BUILTIN_MISC_OPERATION_WITH_SILGEN(CreateAsyncLet, "createAsyncLet", "", Special)
789+
790+
/// asyncLetEnd(): (Builtin.RawPointer) -> Void
791+
BUILTIN_MISC_OPERATION_WITH_SILGEN(EndAsyncLet, "endAsyncLet", "", Special)
792+
785793
/// createAsyncTaskFuture(): (
786794
/// Int, Builtin.NativeObject?, @escaping () async throws -> T
787795
/// ) -> Builtin.NativeObject

include/swift/AST/Builtins.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ bool canBuiltinBeOverloadedForType(BuiltinValueKind ID, Type Ty);
140140
/// createAsyncTask* builtins.
141141
Type getAsyncTaskAndContextType(ASTContext &ctx);
142142

143+
Type getAsyncLetAndTaskType(ASTContext &ctx); // TODO: decide if we use it or not
144+
143145
}
144146

145147
#endif

include/swift/Runtime/Concurrency.h

Lines changed: 83 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#define SWIFT_RUNTIME_CONCURRENCY_H
1919

2020
#include "swift/ABI/TaskGroup.h"
21+
#include "swift/ABI/AsyncLet.h"
2122
#include "swift/ABI/TaskStatus.h"
2223

2324
#pragma clang diagnostic push
@@ -49,15 +50,17 @@ using FutureAsyncSignature =
4950
/// closure.
5051
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
5152
AsyncTaskAndContext swift_task_create_future(
52-
JobFlags flags, const Metadata *futureResultType,
53+
JobFlags flags,
54+
const Metadata *futureResultType,
5355
void *closureEntryPoint,
5456
HeapObject * /* +1 */ closureContext);
5557

5658
/// Create a task object with a future which will run the given
5759
/// function.
5860
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
5961
AsyncTaskAndContext swift_task_create_future_f(
60-
JobFlags flags, const Metadata *futureResultType,
62+
JobFlags flags,
63+
const Metadata *futureResultType,
6164
FutureAsyncSignature::FunctionType *function,
6265
size_t initialContextSize);
6366

@@ -74,7 +77,8 @@ AsyncTaskAndContext swift_task_create_group_future(
7477
/// function, and offer its result to the task group
7578
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
7679
AsyncTaskAndContext swift_task_create_group_future_f(
77-
JobFlags flags, TaskGroup *group,
80+
JobFlags flags,
81+
TaskGroup *group,
7882
const Metadata *futureResultType,
7983
FutureAsyncSignature::FunctionType *function,
8084
size_t initialContextSize);
@@ -169,7 +173,7 @@ SWIFT_CC(swiftasync)
169173
/// \code
170174
/// func swift_taskGroup_wait_next_throwing(
171175
/// waitingTask: Builtin.NativeObject, // current task
172-
/// group: UnsafeRawPointer
176+
/// group: Builtin.RawPointer
173177
/// ) async -> T
174178
/// \endcode
175179
SWIFT_EXPORT_FROM(swift_Concurrency)
@@ -184,8 +188,7 @@ void swift_taskGroup_wait_next_throwing(
184188
/// Its Swift signature is
185189
///
186190
/// \code
187-
/// func swift_taskGroup_initialize(group: Builtin.RawPointer
188-
/// )
191+
/// func swift_taskGroup_initialize(group: Builtin.RawPointer)
189192
/// \endcode
190193
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
191194
void swift_taskGroup_initialize(TaskGroup *group);
@@ -202,7 +205,6 @@ void swift_taskGroup_initialize(TaskGroup *group);
202205
/// \code
203206
/// func swift_taskGroup_attachChild(
204207
/// group: Builtin.RawPointer,
205-
/// parent: Builtin.NativeObject,
206208
/// child: Builtin.NativeObject
207209
/// )
208210
/// \endcode
@@ -214,7 +216,7 @@ void swift_taskGroup_attachChild(TaskGroup *group, AsyncTask *child);
214216
/// This function MUST be called from the AsyncTask running the task group.
215217
///
216218
/// \code
217-
/// func swift_taskGroup_destroy(_ group: UnsafeRawPointer)
219+
/// func swift_taskGroup_destroy(_ group: Builtin.RawPointer)
218220
/// \endcode
219221
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
220222
void swift_taskGroup_destroy(TaskGroup *group);
@@ -244,7 +246,7 @@ bool swift_taskGroup_addPending(TaskGroup *group, bool unconditionally);
244246
/// Its Swift signature is
245247
///
246248
/// \code
247-
/// func swift_taskGroup_cancelAll(group: UnsafeRawPointer)
249+
/// func swift_taskGroup_cancelAll(group: Builtin.RawPointer)
248250
/// \endcode
249251
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
250252
void swift_taskGroup_cancelAll(TaskGroup *group);
@@ -257,7 +259,7 @@ void swift_taskGroup_cancelAll(TaskGroup *group);
257259
/// This can be called from any thread. Its Swift signature is
258260
///
259261
/// \code
260-
/// func swift_taskGroup_isCancelled(group: UnsafeRawPointer)
262+
/// func swift_taskGroup_isCancelled(group: Builtin.RawPointer)
261263
/// \endcode
262264
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
263265
bool swift_taskGroup_isCancelled(TaskGroup *group);
@@ -274,6 +276,76 @@ bool swift_taskGroup_isCancelled(TaskGroup *group);
274276
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
275277
bool swift_taskGroup_isEmpty(TaskGroup *group);
276278

279+
/// Initialize an `AsyncLet` in the passed `asyncLet` memory location.
280+
/// The caller is responsible for retaining and managing the asyncLet's lifecycle.
281+
///
282+
/// Its Swift signature is
283+
///
284+
/// \code
285+
/// func swift_asyncLet_initialize(
286+
/// .... // TODO: fill in
287+
/// )
288+
/// \endcode
289+
//SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
290+
//void swift_asyncLet_initialize(AsyncLet *alet, AsyncTask *task);
291+
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
292+
void swift_asyncLet_initialize(
293+
AsyncLet *alet,
294+
JobFlags flags,
295+
const Metadata *futureResultType,
296+
void *closureEntryPoint,
297+
HeapObject * /* +1 */ closureContext);
298+
299+
/// Its Swift signature is
300+
///
301+
/// \code
302+
/// func swift_asyncLet_start(_ alet: Builtin.RawPointer)
303+
/// \endcode
304+
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
305+
void swift_asyncLet_start(AsyncLet *alet, void* operation);
306+
307+
/// This matches the ABI of a closure `<T>(Builtin.RawPointer) async -> T`
308+
using AsyncLetWaitSignature =
309+
SWIFT_CC(swiftasync)
310+
void(OpaqueValue *,
311+
SWIFT_ASYNC_CONTEXT AsyncContext *, AsyncTask *, Metadata *);
312+
313+
/// Wait for a non-throwing async-let to complete.
314+
///
315+
/// This can be called from any thread. Its Swift signature is
316+
///
317+
/// \code
318+
/// func swift_asyncLet_wait(
319+
/// _ asyncLet: _owned Builtin.RawPointer
320+
/// ) async -> Success
321+
/// \endcode
322+
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swiftasync)
323+
void swift_asyncLet_wait(OpaqueValue *,
324+
SWIFT_ASYNC_CONTEXT AsyncContext *,
325+
AsyncLet *, Metadata *);
326+
327+
/// Wait for a potentially-throwing async-let to complete.
328+
///
329+
/// This can be called from any thread. Its Swift signature is
330+
///
331+
/// \code
332+
/// func swift_asyncLet_wait_throwing(
333+
/// _ asyncLet: _owned Builtin.RawPointer
334+
/// ) async throws -> Success
335+
/// \endcode
336+
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swiftasync)
337+
void swift_asyncLet_wait_throwing(OpaqueValue *,
338+
SWIFT_ASYNC_CONTEXT AsyncContext *,
339+
AsyncLet *, Metadata *);
340+
341+
/// Its Swift signature is
342+
///
343+
/// \code
344+
/// func swift_asyncLet_end(_ alet: Builtin.RawPointer)
345+
/// \endcode
346+
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
347+
void swift_asyncLet_end(AsyncLet *alet);
348+
277349
/// Add a status record to a task. The record should not be
278350
/// modified while it is registered with a task.
279351
///
@@ -314,8 +386,7 @@ bool swift_task_removeStatusRecord(TaskStatusRecord *record);
314386
/// The record must be removed with by the parent invoking
315387
/// `swift_task_detachChild` when the child has completed.
316388
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
317-
ChildTaskStatusRecord*
318-
swift_task_attachChild(AsyncTask *child);
389+
ChildTaskStatusRecord* swift_task_attachChild(AsyncTask *child);
319390

320391
/// Remove a child task from the parent tracking it.
321392
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1541,7 +1541,8 @@ FUNCTION(TaskCreateFunc,
15411541
// AsyncTaskAndContext swift_task_create_future(
15421542
// size_t flags,
15431543
// const Metadata *futureResultType,
1544-
// void *closureEntry, HeapObject *closureContext);
1544+
// void *closureEntry,
1545+
// HeapObject *closureContext);
15451546
FUNCTION(TaskCreateFuture,
15461547
swift_task_create_future, SwiftCC,
15471548
ConcurrencyAvailability,
@@ -1553,7 +1554,8 @@ FUNCTION(TaskCreateFuture,
15531554
// AsyncTaskAndContext swift_task_create_future_f(
15541555
// size_t flags,
15551556
// const Metadata *futureResultType,
1556-
// TaskContinuationFunction *function, size_t contextSize);
1557+
// TaskContinuationFunction *function,
1558+
// size_t contextSize);
15571559
FUNCTION(TaskCreateFutureFunc,
15581560
swift_task_create_future_f, SwiftCC,
15591561
ConcurrencyAvailability,
@@ -1563,9 +1565,11 @@ FUNCTION(TaskCreateFutureFunc,
15631565
ATTRS(NoUnwind, ArgMemOnly))
15641566

15651567
// AsyncTaskAndContext swift_task_create_group_future(
1566-
// size_t flags, TaskGroup *group,
1568+
// size_t flags,
1569+
// TaskGroup *group,
15671570
// const Metadata *futureResultType,
1568-
// void *closureEntry, HeapObject *closureContext);
1571+
// void *closureEntry,
1572+
// HeapObject *closureContext);
15691573
FUNCTION(TaskCreateGroupFuture,
15701574
swift_task_create_group_future, SwiftCC,
15711575
ConcurrencyAvailability,
@@ -1576,9 +1580,11 @@ FUNCTION(TaskCreateGroupFuture,
15761580
ATTRS(NoUnwind, ArgMemOnly))
15771581

15781582
// AsyncTaskAndContext swift_task_create_group_future_f(
1579-
// size_t flags, TaskGroup *group,
1583+
// size_t flags,
1584+
// TaskGroup *group,
15801585
// const Metadata *futureResultType,
1581-
// TaskContinuationFunction *function, size_t contextSize);
1586+
// TaskContinuationFunction *function,
1587+
// size_t contextSize);
15821588
FUNCTION(TaskCreateGroupFutureFunc,
15831589
swift_task_create_group_future_f, SwiftCC,
15841590
ConcurrencyAvailability,
@@ -1672,6 +1678,34 @@ FUNCTION(DefaultActorDeallocateResilient,
16721678
ARGS(RefCountedPtrTy),
16731679
ATTRS(NoUnwind))
16741680

1681+
// void swift_asyncLet_initialize(
1682+
// AsyncLet *alet,
1683+
// size_t flags,
1684+
// // FIXME: or is it TaskContinuationFunction* function ?????? like in TaskCreateFunc
1685+
// const Metadata *futureResultType,
1686+
// void *closureEntry,
1687+
// // TODO: do we need the context after all???? HeapObject *closureContext
1688+
// );
1689+
FUNCTION(AsyncLetInitialize,
1690+
swift_asyncLet_initialize, SwiftCC,
1691+
ConcurrencyAvailability,
1692+
RETURNS(VoidTy),
1693+
ARGS(SwiftAsyncLetPtrTy, // AsyncLet*, alias for Int8PtrTy
1694+
SizeTy, // flags
1695+
TypeMetadataPtrTy, // futureResultType
1696+
Int8PtrTy, // closureEntry
1697+
RefCountedPtrTy, // closureContext
1698+
),
1699+
ATTRS(NoUnwind, ArgMemOnly))
1700+
1701+
// void swift_asyncLet_end(AsyncLet *alet);
1702+
FUNCTION(EndAsyncLet,
1703+
swift_asyncLet_end, SwiftCC,
1704+
ConcurrencyAvailability,
1705+
RETURNS(VoidTy),
1706+
ARGS(SwiftAsyncLetPtrTy),
1707+
ATTRS(NoUnwind))
1708+
16751709
// void swift_taskGroup_initialize(TaskGroup *group);
16761710
FUNCTION(TaskGroupInitialize,
16771711
swift_taskGroup_initialize, SwiftCC,

0 commit comments

Comments
 (0)