Skip to content

Commit ae9e531

Browse files
committed
[Concurrency] Introduce TaskOptionRecord for spawn options
1 parent 038af80 commit ae9e531

24 files changed

+259
-108
lines changed

include/swift/ABI/MetadataValues.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2101,6 +2101,12 @@ enum class TaskStatusRecordKind : uint8_t {
21012101
Private_RecordLock = 192
21022102
};
21032103

2104+
/// Kinds of option records that can be passed to creating asynchronous tasks.
2105+
enum class TaskOptionRecordKind : uint8_t {
2106+
/// Request a task to be kicked off, or resumed, on a specific executor.
2107+
Executor = 0,
2108+
};
2109+
21042110
/// Flags for cancellation records.
21052111
class TaskStatusRecordFlags : public FlagSet<size_t> {
21062112
public:

include/swift/ABI/Task.h

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,73 @@ inline void Job::runInFullyEstablishedContext() {
529529
return runSimpleInFullyEstablishedContext(); // 'return' forces tail call
530530
}
531531

532+
// ==== ------------------------------------------------------------------------
533+
// ==== Task Options, for creating and waiting on tasks
534+
535+
/// Flags for task option records.
536+
class TaskOptionRecordFlags : public FlagSet<size_t> {
537+
public:
538+
enum {
539+
Kind = 0,
540+
Kind_width = 8,
541+
};
542+
543+
explicit TaskOptionRecordFlags(size_t bits) : FlagSet(bits) {}
544+
constexpr TaskOptionRecordFlags() {}
545+
TaskOptionRecordFlags(TaskOptionRecordKind kind) {
546+
setKind(kind);
547+
}
548+
549+
FLAGSET_DEFINE_FIELD_ACCESSORS(Kind, Kind_width, TaskOptionRecordKind,
550+
getKind, setKind)
551+
};
552+
553+
/// The abstract base class for all options that may be used
554+
/// to configure a newly spawned task.
555+
class TaskOptionRecord {
556+
public:
557+
TaskOptionRecordFlags Flags;
558+
TaskOptionRecord *Parent;
559+
560+
TaskOptionRecord(TaskOptionRecordKind kind,
561+
TaskOptionRecord *parent = nullptr)
562+
: Flags(kind) {
563+
Parent = parent;
564+
}
565+
566+
TaskOptionRecord(const TaskOptionRecord &) = delete;
567+
TaskOptionRecord &operator=(const TaskOptionRecord &) = delete;
568+
569+
TaskOptionRecordKind getKind() const {
570+
return Flags.getKind();
571+
}
572+
573+
TaskOptionRecord *getParent() const {
574+
return Parent;
575+
}
576+
577+
};
578+
579+
/// Task option to specify on what executor the task should be executed.
580+
///
581+
/// Not passing this option implies that that a "best guess" or good default
582+
/// executor should be used instead, most often this may mean the global
583+
/// concurrent executor, or the enclosing actor's executor.
584+
class ExecutorTaskOptionRecord : public TaskOptionRecord {
585+
ExecutorRef *Executor;
586+
587+
public:
588+
ExecutorTaskOptionRecord(ExecutorRef *executor)
589+
: TaskOptionRecord(TaskOptionRecordKind::Executor),
590+
Executor(executor) {}
591+
592+
ExecutorRef *getExecutor() const {
593+
return Executor;
594+
}
595+
};
596+
597+
// ==== ------------------------------------------------------------------------
598+
532599
/// An asynchronous context within a task. Generally contexts are
533600
/// allocated using the task-local stack alloc/dealloc operations, but
534601
/// there's no guarantee of that, and the ABI is designed to permit

include/swift/AST/Builtins.def

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -803,7 +803,9 @@ BUILTIN_MISC_OPERATION(StartAsyncLet, "startAsyncLet", "", Special)
803803
BUILTIN_MISC_OPERATION_WITH_SILGEN(EndAsyncLet, "endAsyncLet", "", Special)
804804

805805
/// createAsyncTaskFuture(): (
806-
/// Int, Builtin.NativeObject?, @escaping () async throws -> T
806+
/// Int, // flags
807+
/// Builtin.RawPointer?, // options (TaskOptionRecord*)
808+
/// @escaping () async throws -> T // function
807809
/// ) -> Builtin.NativeObject
808810
///
809811
/// Create a new asynchronous task future, given flags, an (optional) parent
@@ -812,10 +814,10 @@ BUILTIN_MISC_OPERATION_WITH_SILGEN(CreateAsyncTaskFuture,
812814
"createAsyncTaskFuture", "", Special)
813815

814816
/// createAsyncTaskGroupFuture(): (
815-
/// Int, // flags
816-
/// Builtin.NativeObject?, // parent
817-
/// Builtin.RawPointer?, // group
818-
/// @escaping () async throws -> T
817+
/// Int, // flags
818+
/// Builtin.RawPointer?, // group
819+
/// Builtin.RawPointer?, // options (TaskOptionRecord*)
820+
/// @escaping () async throws -> T // function
819821
/// ) -> Builtin.NativeObject
820822
///
821823
/// Create a new asynchronous task future, given flags, a parent task,

include/swift/Runtime/Concurrency.h

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,10 @@ struct AsyncTaskAndContext {
3838
/// Create a task object with no future which will run the given
3939
/// function.
4040
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
41-
AsyncTaskAndContext swift_task_create_f(size_t flags,
42-
ThinNullaryAsyncSignature::FunctionType *function,
43-
size_t initialContextSize);
41+
AsyncTaskAndContext swift_task_create_f(
42+
size_t flags,
43+
TaskOptionRecord *options,
44+
ThinNullaryAsyncSignature::FunctionType *function, size_t initialContextSize);
4445

4546
/// Caution: not all future-initializing functions actually throw, so
4647
/// this signature may be incorrect.
@@ -52,37 +53,38 @@ using FutureAsyncSignature =
5253
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
5354
AsyncTaskAndContext swift_task_create_future(
5455
size_t flags,
56+
TaskOptionRecord *options,
5557
const Metadata *futureResultType,
56-
void *closureEntryPoint,
57-
HeapObject * /* +1 */ closureContext);
58+
void *closureEntryPoint, HeapObject * /* +1 */ closureContext);
5859

5960
/// Create a task object with a future which will run the given
6061
/// function.
6162
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
6263
AsyncTaskAndContext swift_task_create_future_f(
6364
size_t flags,
65+
TaskOptionRecord *options,
6466
const Metadata *futureResultType,
65-
FutureAsyncSignature::FunctionType *function,
66-
size_t initialContextSize);
67+
FutureAsyncSignature::FunctionType *function, size_t initialContextSize);
6768

6869
/// Create a task object with a future which will run the given
6970
/// closure, and offer its result to the task group
7071
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
7172
AsyncTaskAndContext swift_task_create_group_future(
72-
size_t flags, TaskGroup *group,
73+
size_t flags,
74+
TaskGroup *group,
75+
TaskOptionRecord *options,
7376
const Metadata *futureResultType,
74-
void *closureEntryPoint,
75-
HeapObject * /* +1 */ closureContext);
77+
void *closureEntryPoint, HeapObject * /* +1 */ closureContext);
7678

7779
/// Create a task object with a future which will run the given
7880
/// function, and offer its result to the task group
7981
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
8082
AsyncTaskAndContext swift_task_create_group_future_f(
8183
size_t flags,
8284
TaskGroup *group,
85+
TaskOptionRecord *options,
8386
const Metadata *futureResultType,
84-
FutureAsyncSignature::FunctionType *function,
85-
size_t initialContextSize);
87+
FutureAsyncSignature::FunctionType *function, size_t initialContextSize);
8688

8789
/// Allocate memory in a task.
8890
///
@@ -282,15 +284,15 @@ bool swift_taskGroup_isEmpty(TaskGroup *group);
282284
/// \code
283285
/// func swift_asyncLet_start<T>(
284286
/// _ alet: Builtin.RawPointer,
287+
/// _ options: Builtin.RawPointer?,
285288
/// operation: __owned @Sendable () async throws -> T
286289
/// )
287290
/// \endcode
288291
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
289-
void swift_asyncLet_start(
290-
AsyncLet *alet,
291-
const Metadata *futureResultType,
292-
void *closureEntryPoint,
293-
void *closureContext);
292+
void swift_asyncLet_start(AsyncLet *alet,
293+
TaskOptionRecord *options,
294+
const Metadata *futureResultType,
295+
void *closureEntryPoint, void *closureContext);
294296

295297
/// This matches the ABI of a closure `<T>(Builtin.RawPointer) async -> T`
296298
using AsyncLetWaitSignature =

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1549,67 +1549,77 @@ FUNCTION(TaskCancel,
15491549

15501550
// AsyncTaskAndContext swift_task_create_f(
15511551
// size_t flags,
1552-
// TaskContinuationFunction* function,
1553-
// size_t contextSize);
1552+
// TaskOptionRecord *options,
1553+
// TaskContinuationFunction* function, size_t contextSize);
15541554
FUNCTION(TaskCreateFunc,
15551555
swift_task_create_f, SwiftCC,
15561556
ConcurrencyAvailability,
15571557
RETURNS(AsyncTaskAndContextTy),
1558-
ARGS(SizeTy, TaskContinuationFunctionPtrTy, SizeTy),
1558+
ARGS(SizeTy,
1559+
SwiftTaskOptionRecordPtrTy,
1560+
TaskContinuationFunctionPtrTy, SizeTy),
15591561
ATTRS(NoUnwind, ArgMemOnly))
15601562

15611563
// AsyncTaskAndContext swift_task_create_future(
15621564
// size_t flags,
1565+
// TaskOptionRecord *options,
15631566
// const Metadata *futureResultType,
1564-
// void *closureEntry,
1565-
// HeapObject *closureContext);
1567+
// void *closureEntry, HeapObject *closureContext);
15661568
FUNCTION(TaskCreateFuture,
15671569
swift_task_create_future, SwiftCC,
15681570
ConcurrencyAvailability,
15691571
RETURNS(AsyncTaskAndContextTy),
1570-
ARGS(SizeTy, TypeMetadataPtrTy,
1572+
ARGS(SizeTy,
1573+
SwiftTaskOptionRecordPtrTy,
1574+
TypeMetadataPtrTy,
15711575
Int8PtrTy, RefCountedPtrTy),
15721576
ATTRS(NoUnwind, ArgMemOnly))
15731577

15741578
// AsyncTaskAndContext swift_task_create_future_f(
15751579
// size_t flags,
1580+
// TaskOptionRecord *options,
15761581
// const Metadata *futureResultType,
1577-
// TaskContinuationFunction *function,
1578-
// size_t contextSize);
1582+
// TaskContinuationFunction *function, size_t contextSize);
15791583
FUNCTION(TaskCreateFutureFunc,
15801584
swift_task_create_future_f, SwiftCC,
15811585
ConcurrencyAvailability,
15821586
RETURNS(AsyncTaskAndContextTy),
1583-
ARGS(SizeTy, TypeMetadataPtrTy,
1587+
ARGS(SizeTy,
1588+
SwiftTaskOptionRecordPtrTy,
1589+
TypeMetadataPtrTy,
15841590
TaskContinuationFunctionPtrTy, SizeTy),
15851591
ATTRS(NoUnwind, ArgMemOnly))
15861592

15871593
// AsyncTaskAndContext swift_task_create_group_future(
15881594
// size_t flags,
15891595
// TaskGroup *group,
1596+
// TaskOptionRecord *options
15901597
// const Metadata *futureResultType,
1591-
// void *closureEntry,
1592-
// HeapObject *closureContext);
1598+
// void *closureEntry, HeapObject *closureContext);
15931599
FUNCTION(TaskCreateGroupFuture,
15941600
swift_task_create_group_future, SwiftCC,
15951601
ConcurrencyAvailability,
15961602
RETURNS(AsyncTaskAndContextTy),
1597-
ARGS(SizeTy, SwiftTaskGroupPtrTy,
1603+
ARGS(SizeTy,
1604+
SwiftTaskGroupPtrTy,
1605+
SwiftTaskOptionRecordPtrTy,
15981606
TypeMetadataPtrTy,
15991607
Int8PtrTy, RefCountedPtrTy),
16001608
ATTRS(NoUnwind, ArgMemOnly))
16011609

16021610
// AsyncTaskAndContext swift_task_create_group_future_f(
16031611
// size_t flags,
16041612
// TaskGroup *group,
1613+
// TaskOptionRecord *options
16051614
// const Metadata *futureResultType,
1606-
// TaskContinuationFunction *function,
1607-
// size_t contextSize);
1615+
// TaskContinuationFunction *function, size_t contextSize);
16081616
FUNCTION(TaskCreateGroupFutureFunc,
16091617
swift_task_create_group_future_f, SwiftCC,
16101618
ConcurrencyAvailability,
16111619
RETURNS(AsyncTaskAndContextTy),
1612-
ARGS(SizeTy, SwiftTaskGroupPtrTy,
1620+
ARGS(SizeTy,
1621+
SwiftTaskGroupPtrTy,
1622+
SwiftTaskOptionRecordPtrTy,
16131623
TypeMetadataPtrTy,
16141624
TaskContinuationFunctionPtrTy, SizeTy),
16151625
ATTRS(NoUnwind, ArgMemOnly))
@@ -1716,6 +1726,7 @@ FUNCTION(DistributedActorDestroy,
17161726

17171727
/// void swift_asyncLet_start(
17181728
/// AsyncLet *alet,
1729+
/// TaskOptionRecord *options,
17191730
/// const Metadata *futureResultType,
17201731
/// void *closureEntryPoint,
17211732
/// OpaqueValue *closureContext
@@ -1724,10 +1735,11 @@ FUNCTION(AsyncLetStart,
17241735
swift_asyncLet_start, SwiftCC,
17251736
ConcurrencyAvailability,
17261737
RETURNS(VoidTy),
1727-
ARGS(SwiftAsyncLetPtrTy, // AsyncLet*, alias for Int8PtrTy
1728-
TypeMetadataPtrTy, // futureResultType
1729-
Int8PtrTy, // closureEntry
1730-
OpaquePtrTy, // closureContext
1738+
ARGS(SwiftAsyncLetPtrTy, // AsyncLet*, alias for Int8PtrTy
1739+
SwiftTaskOptionRecordPtrTy, // options
1740+
TypeMetadataPtrTy, // futureResultType
1741+
Int8PtrTy, // closureEntry
1742+
OpaquePtrTy, // closureContext
17311743
),
17321744
ATTRS(NoUnwind, ArgMemOnly))
17331745

lib/AST/Builtins.cpp

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1427,24 +1427,29 @@ Type swift::getAsyncTaskAndContextType(ASTContext &ctx) {
14271427
static ValueDecl *getCreateAsyncTaskFuture(ASTContext &ctx, Identifier id) {
14281428
BuiltinFunctionBuilder builder(ctx);
14291429
auto genericParam = makeGenericParam().build(builder);
1430-
builder.addParameter(makeConcrete(ctx.getIntType()));
1430+
builder.addParameter(makeConcrete(ctx.getIntType())); // 0 flags
1431+
builder.addParameter(
1432+
makeConcrete(OptionalType::get(ctx.TheRawPointerType))); // 1 options
14311433
auto extInfo = ASTExtInfoBuilder().withAsync().withThrows().build();
14321434
builder.addParameter(
1433-
makeConcrete(FunctionType::get({ }, genericParam, extInfo)));
1435+
makeConcrete(FunctionType::get({ }, genericParam, extInfo))); // 2 function
14341436
builder.setResult(makeConcrete(getAsyncTaskAndContextType(ctx)));
14351437
return builder.build(id);
14361438
}
14371439

14381440
static ValueDecl *getCreateAsyncTaskGroupFuture(ASTContext &ctx, Identifier id) {
14391441
BuiltinFunctionBuilder builder(ctx);
14401442
auto genericParam = makeGenericParam().build(builder);
1441-
builder.addParameter(makeConcrete(ctx.getIntType())); // flags
1443+
builder.addParameter(makeConcrete(ctx.getIntType())); // 0 flags
1444+
builder.addParameter(
1445+
makeConcrete(OptionalType::get(ctx.TheRawPointerType))); // 1 group
14421446
builder.addParameter(
1443-
makeConcrete(OptionalType::get(ctx.TheRawPointerType))); // group
1447+
makeConcrete(OptionalType::get(ctx.TheRawPointerType))); // 2 options
14441448
auto extInfo = ASTExtInfoBuilder().withAsync().withThrows().build();
14451449
builder.addParameter(
1446-
makeConcrete(FunctionType::get({ }, genericParam, extInfo)));
1447-
builder.setResult(makeConcrete(getAsyncTaskAndContextType(ctx)));
1450+
makeConcrete(FunctionType::get({ }, genericParam, extInfo))); // 3 operation
1451+
builder.setResult(makeConcrete(getAsyncTaskAndContextType(ctx))); // 4 context
1452+
14481453
return builder.build(id);
14491454
}
14501455

lib/IRGen/GenBuiltin.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,9 +229,11 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
229229
if (Builtin.ID == BuiltinValueKind::StartAsyncLet) {
230230
auto taskFunction = args.claimNext();
231231
auto taskContext = args.claimNext();
232+
auto taskOptions = args.claimNext();
232233

233234
auto asyncLet = emitBuiltinStartAsyncLet(
234235
IGF,
236+
taskOptions,
235237
taskFunction,
236238
taskContext,
237239
substitutions
@@ -274,6 +276,7 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
274276
(Builtin.ID == BuiltinValueKind::CreateAsyncTaskGroupFuture)
275277
? args.claimNext()
276278
: nullptr;
279+
auto taskOptions = args.claimNext();
277280
auto futureResultType =
278281
((Builtin.ID == BuiltinValueKind::CreateAsyncTaskFuture) ||
279282
(Builtin.ID == BuiltinValueKind::CreateAsyncTaskGroupFuture))
@@ -283,7 +286,12 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
283286
auto taskContext = args.claimNext();
284287

285288
auto newTaskAndContext = emitTaskCreate(
286-
IGF, flags, taskGroup, futureResultType, taskFunction, taskContext,
289+
IGF,
290+
flags,
291+
taskGroup,
292+
taskOptions,
293+
futureResultType,
294+
taskFunction, taskContext,
287295
substitutions);
288296

289297
// Cast back to NativeObject/RawPointer.

0 commit comments

Comments
 (0)