Skip to content

Commit 4363459

Browse files
authored
Merge pull request #69568 from ktoso/wip-prepare-task-executor-protocol
Task Executors: Prepare for new TaskExecutor protocol
2 parents 10466ec + c29bffd commit 4363459

32 files changed

+243
-112
lines changed

include/swift/ABI/Executor.h

Lines changed: 99 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ class AsyncTask;
2828
class DefaultActor;
2929
class Job;
3030
class SerialExecutorWitnessTable;
31+
class TaskExecutorWitnessTable;
3132

32-
/// An unmanaged reference to an executor.
33+
/// An unmanaged reference to a serial executor.
3334
///
3435
/// This type corresponds to the type Optional<Builtin.Executor> in
3536
/// Swift. The representation of nil in Optional<Builtin.Executor>
@@ -53,7 +54,7 @@ class SerialExecutorWitnessTable;
5354
/// bits off before accessing the witness table, so setting them
5455
/// in the future should back-deploy as long as the witness table
5556
/// reference is still present.
56-
class ExecutorRef {
57+
class SerialExecutorRef {
5758
HeapObject *Identity; // Not necessarily Swift reference-countable
5859
uintptr_t Implementation;
5960

@@ -79,7 +80,7 @@ class ExecutorRef {
7980

8081
static_assert(static_cast<uintptr_t>(ExecutorKind::Ordinary) == 0);
8182

82-
constexpr ExecutorRef(HeapObject *identity, uintptr_t implementation)
83+
constexpr SerialExecutorRef(HeapObject *identity, uintptr_t implementation)
8384
: Identity(identity), Implementation(implementation) {}
8485

8586
public:
@@ -88,35 +89,35 @@ class ExecutorRef {
8889
/// environment, it's presumed to be okay to switch synchronously
8990
/// to an actor. As an executor request, this represents a request
9091
/// to drop whatever the current actor is.
91-
constexpr static ExecutorRef generic() {
92-
return ExecutorRef(nullptr, 0);
92+
constexpr static SerialExecutorRef generic() {
93+
return SerialExecutorRef(nullptr, 0);
9394
}
9495

9596
/// Given a pointer to a default actor, return an executor reference
9697
/// for it.
97-
static ExecutorRef forDefaultActor(DefaultActor *actor) {
98+
static SerialExecutorRef forDefaultActor(DefaultActor *actor) {
9899
assert(actor);
99-
return ExecutorRef(actor, 0);
100+
return SerialExecutorRef(actor, 0);
100101
}
101102

102103
/// Given a pointer to a serial executor and its SerialExecutor
103104
/// conformance, return an executor reference for it.
104-
static ExecutorRef forOrdinary(HeapObject *identity,
105+
static SerialExecutorRef forOrdinary(HeapObject *identity,
105106
const SerialExecutorWitnessTable *witnessTable) {
106107
assert(identity);
107108
assert(witnessTable);
108109
auto wtable = reinterpret_cast<uintptr_t>(witnessTable) |
109110
static_cast<uintptr_t>(ExecutorKind::Ordinary);
110-
return ExecutorRef(identity, wtable);
111+
return SerialExecutorRef(identity, wtable);
111112
}
112113

113-
static ExecutorRef forComplexEquality(HeapObject *identity,
114+
static SerialExecutorRef forComplexEquality(HeapObject *identity,
114115
const SerialExecutorWitnessTable *witnessTable) {
115116
assert(identity);
116117
assert(witnessTable);
117118
auto wtable = reinterpret_cast<uintptr_t>(witnessTable) |
118119
static_cast<uintptr_t>(ExecutorKind::ComplexEquality);
119-
return ExecutorRef(identity, wtable);
120+
return SerialExecutorRef(identity, wtable);
120121
}
121122

122123
HeapObject *getIdentity() const {
@@ -162,7 +163,7 @@ class ExecutorRef {
162163

163164
/// Do we have to do any work to start running as the requested
164165
/// executor?
165-
bool mustSwitchToRun(ExecutorRef newExecutor) const {
166+
bool mustSwitchToRun(SerialExecutorRef newExecutor) const {
166167
return Identity != newExecutor.Identity;
167168
}
168169

@@ -174,10 +175,94 @@ class ExecutorRef {
174175
return Implementation & WitnessTableMask;
175176
}
176177

177-
bool operator==(ExecutorRef other) const {
178+
bool operator==(SerialExecutorRef other) const {
178179
return Identity == other.Identity;
179180
}
180-
bool operator!=(ExecutorRef other) const {
181+
bool operator!=(SerialExecutorRef other) const {
182+
return !(*this == other);
183+
}
184+
};
185+
186+
class TaskExecutorRef {
187+
HeapObject *Identity; // Not necessarily Swift reference-countable
188+
uintptr_t Implementation;
189+
190+
// We future-proof the ABI here by masking the low bits off the
191+
// implementation pointer before using it as a witness table.
192+
//
193+
// We have 3 bits for future use remaining here.
194+
enum: uintptr_t {
195+
WitnessTableMask = ~uintptr_t(alignof(void*) - 1)
196+
};
197+
198+
/// The kind is stored in the free bits in the `Implementation` witness table reference.
199+
enum class TaskExecutorKind : uintptr_t {
200+
/// Ordinary executor.
201+
Ordinary = 0b00,
202+
};
203+
204+
static_assert(static_cast<uintptr_t>(TaskExecutorKind::Ordinary) == 0);
205+
206+
constexpr TaskExecutorRef(HeapObject *identity, uintptr_t implementation)
207+
: Identity(identity), Implementation(implementation) {}
208+
209+
public:
210+
211+
constexpr static TaskExecutorRef undefined() {
212+
return TaskExecutorRef(nullptr, 0);
213+
}
214+
215+
/// Given a pointer to a serial executor and its TaskExecutor
216+
/// conformance, return an executor reference for it.
217+
static TaskExecutorRef forOrdinary(HeapObject *identity,
218+
const SerialExecutorWitnessTable *witnessTable) {
219+
assert(identity);
220+
assert(witnessTable);
221+
auto wtable = reinterpret_cast<uintptr_t>(witnessTable) |
222+
static_cast<uintptr_t>(TaskExecutorKind::Ordinary);
223+
return TaskExecutorRef(identity, wtable);
224+
}
225+
226+
HeapObject *getIdentity() const {
227+
return Identity;
228+
}
229+
230+
/// Is this the generic executor reference?
231+
bool isUndefined() const {
232+
return Identity == 0;
233+
}
234+
235+
TaskExecutorKind getExecutorKind() const {
236+
return static_cast<TaskExecutorKind>(Implementation & ~WitnessTableMask);
237+
}
238+
239+
/// Is this an ordinary executor reference?
240+
/// These executor references are the default kind, and have no special treatment elsewhere in the system.
241+
bool isOrdinary() const {
242+
return getExecutorKind() == TaskExecutorKind::Ordinary;
243+
}
244+
245+
const TaskExecutorWitnessTable *getTaskExecutorWitnessTable() const {
246+
assert(!isUndefined());
247+
auto table = Implementation & WitnessTableMask;
248+
return reinterpret_cast<const TaskExecutorWitnessTable*>(table);
249+
}
250+
251+
// /// Do we have to do any work to start running as the requested
252+
// /// executor?
253+
// bool mustSwitchToRun(TaskExecutorRef newExecutor) const {
254+
// return Identity != newExecutor.Identity;
255+
// }
256+
257+
/// Get the raw value of the Implementation field, for tracing.
258+
uintptr_t getRawImplementation() const {
259+
return Implementation & WitnessTableMask;
260+
}
261+
262+
bool operator==(TaskExecutorRef other) const {
263+
return Identity == other.Identity;
264+
}
265+
bool operator!=(TaskExecutorRef other) const {
181266
return !(*this == other);
182267
}
183268
};

include/swift/ABI/Task.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ class AsyncTask : public Job {
400400
public:
401401
/// Flag that the task is to be enqueued on the provided executor and actually
402402
/// enqueue it
403-
void flagAsAndEnqueueOnExecutor(ExecutorRef newExecutor);
403+
void flagAsAndEnqueueOnExecutor(SerialExecutorRef newExecutor);
404404

405405
/// Flag that this task is now completed. This normally does not do anything
406406
/// but can be used to locally insert logging.
@@ -790,7 +790,7 @@ class ContinuationAsyncContext : public AsyncContext {
790790

791791
/// The executor that should be resumed to.
792792
/// Public ABI.
793-
ExecutorRef ResumeToExecutor;
793+
SerialExecutorRef ResumeToExecutor;
794794

795795
#if defined(SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY)
796796
/// In a task-to-thread model, instead of voluntarily descheduling the task

include/swift/ABI/TaskOptions.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,14 @@ class TaskGroupTaskOptionRecord : public TaskOptionRecord {
8282
/// executor should be used instead, most often this may mean the global
8383
/// concurrent executor, or the enclosing actor's executor.
8484
class ExecutorTaskOptionRecord : public TaskOptionRecord {
85-
const ExecutorRef Executor;
85+
const SerialExecutorRef Executor;
8686

8787
public:
88-
ExecutorTaskOptionRecord(ExecutorRef executor)
88+
ExecutorTaskOptionRecord(SerialExecutorRef executor)
8989
: TaskOptionRecord(TaskOptionRecordKind::Executor),
9090
Executor(executor) {}
9191

92-
ExecutorRef getExecutor() const {
92+
SerialExecutorRef getExecutor() const {
9393
return Executor;
9494
}
9595

include/swift/ABI/TaskStatus.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ class TaskDependencyStatusRecord : public TaskStatusRecord {
321321
// (potentially intrusively), so that the appropriate escalation effect
322322
// (which may be different for each type of executor) can happen if a task
323323
// is escalated while enqueued.
324-
ExecutorRef Executor;
324+
SerialExecutorRef Executor;
325325
} DependentOn;
326326

327327
// Enum specifying the type of dependency this task has
@@ -359,7 +359,7 @@ class TaskDependencyStatusRecord : public TaskStatusRecord {
359359
DependentOn.TaskGroup = taskGroup;
360360
}
361361

362-
TaskDependencyStatusRecord(AsyncTask *waitingTask, ExecutorRef executor) :
362+
TaskDependencyStatusRecord(AsyncTask *waitingTask, SerialExecutorRef executor) :
363363
TaskStatusRecord(TaskStatusRecordKind::TaskDependency),
364364
DependencyKind(EnqueuedOnExecutor), WaitingTask(waitingTask) {
365365
DependentOn.Executor = executor;
@@ -369,7 +369,7 @@ class TaskDependencyStatusRecord : public TaskStatusRecord {
369369
return record->getKind() == TaskStatusRecordKind::TaskDependency;
370370
}
371371

372-
void updateDependencyToEnqueuedOn(ExecutorRef executor) {
372+
void updateDependencyToEnqueuedOn(SerialExecutorRef executor) {
373373
DependencyKind = EnqueuedOnExecutor;
374374
DependentOn.Executor = executor;
375375
}

include/swift/AST/ASTSynthesis.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ enum SingletonTypeSynthesizer {
5050
_void,
5151
_word,
5252
_serialExecutor,
53+
_taskExecutor,
5354
};
5455
inline Type synthesizeType(SynthesisContext &SC,
5556
SingletonTypeSynthesizer kind) {
@@ -69,6 +70,9 @@ inline Type synthesizeType(SynthesisContext &SC,
6970
case _serialExecutor:
7071
return SC.Context.getProtocol(KnownProtocolKind::SerialExecutor)
7172
->getDeclaredInterfaceType();
73+
case _taskExecutor:
74+
return SC.Context.getProtocol(KnownProtocolKind::TaskExecutor)
75+
->getDeclaredInterfaceType();
7276
}
7377
}
7478

include/swift/AST/Builtins.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -874,7 +874,7 @@ BUILTIN_MISC_OPERATION_WITH_SILGEN(Alignof, "alignof", "n", Special)
874874

875875
// getCurrentExecutor: () async -> Builtin.Executor?
876876
//
877-
// Retrieve the ExecutorRef on which the current asynchronous
877+
// Retrieve the SerialExecutorRef on which the current asynchronous
878878
// function is executing, or nil if the function isn't running
879879
// anywhere in particular.
880880
BUILTIN_MISC_OPERATION_WITH_SILGEN(GetCurrentExecutor, "getCurrentExecutor", "", Special)

include/swift/AST/KnownProtocols.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ PROTOCOL(FixedWidthInteger)
8686
PROTOCOL(RangeReplaceableCollection)
8787
PROTOCOL(Executor)
8888
PROTOCOL(SerialExecutor)
89+
PROTOCOL(TaskExecutor)
8990
PROTOCOL(GlobalActor)
9091

9192
PROTOCOL_(BridgedNSError)

include/swift/AST/KnownSDKTypes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ KNOWN_SDK_TYPE_DECL(Concurrency, Job, StructDecl, 0) // TODO: remove in favor of
4444
KNOWN_SDK_TYPE_DECL(Concurrency, ExecutorJob, StructDecl, 0)
4545
KNOWN_SDK_TYPE_DECL(Concurrency, UnownedJob, StructDecl, 0)
4646
KNOWN_SDK_TYPE_DECL(Concurrency, Executor, NominalTypeDecl, 0)
47+
KNOWN_SDK_TYPE_DECL(Concurrency, TaskExecutor, NominalTypeDecl, 0)
4748
KNOWN_SDK_TYPE_DECL(Concurrency, SerialExecutor, NominalTypeDecl, 0)
4849
KNOWN_SDK_TYPE_DECL(Concurrency, UnownedSerialExecutor, NominalTypeDecl, 0)
4950

include/swift/AST/Types.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1696,7 +1696,7 @@ class BuiltinRawUnsafeContinuationType : public BuiltinType {
16961696
DEFINE_EMPTY_CAN_TYPE_WRAPPER(BuiltinRawUnsafeContinuationType, BuiltinType)
16971697

16981698
/// BuiltinExecutorType - The builtin executor-ref type. In C, this
1699-
/// is the ExecutorRef struct type.
1699+
/// is the SerialExecutorRef struct type.
17001700
class BuiltinExecutorType : public BuiltinType {
17011701
friend class ASTContext;
17021702
BuiltinExecutorType(const ASTContext &C)

include/swift/Demangling/StandardTypesMangling.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ STANDARD_TYPE_CONCURRENCY(Protocol, F, Executor)
8888
STANDARD_TYPE_CONCURRENCY(Protocol, f, SerialExecutor)
8989
STANDARD_TYPE_CONCURRENCY(Structure, G, TaskGroup)
9090
STANDARD_TYPE_CONCURRENCY(Structure, g, ThrowingTaskGroup)
91+
STANDARD_TYPE_CONCURRENCY(Protocol, h, TaskExecutor)
9192
STANDARD_TYPE_CONCURRENCY(Protocol, I, AsyncIteratorProtocol)
9293
STANDARD_TYPE_CONCURRENCY(Protocol, i, AsyncSequence)
9394
STANDARD_TYPE_CONCURRENCY(Structure, J, UnownedJob)

include/swift/Runtime/Concurrency.h

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,7 @@ void swift_task_localsCopyTo(AsyncTask* target);
660660
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swiftasync)
661661
void swift_task_switch(SWIFT_ASYNC_CONTEXT AsyncContext *resumeToContext,
662662
TaskContinuationFunction *resumeFunction,
663-
ExecutorRef newExecutor);
663+
SerialExecutorRef newExecutor);
664664

665665
/// Mark a task for enqueue on a new executor and then enqueue it.
666666
///
@@ -671,7 +671,7 @@ void swift_task_switch(SWIFT_ASYNC_CONTEXT AsyncContext *resumeToContext,
671671
/// synchronously when possible.
672672
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
673673
void
674-
swift_task_enqueueTaskOnExecutor(AsyncTask *task, ExecutorRef executor);
674+
swift_task_enqueueTaskOnExecutor(AsyncTask *task, SerialExecutorRef executor);
675675

676676
/// Enqueue the given job to run asynchronously on the given executor.
677677
///
@@ -681,7 +681,7 @@ swift_task_enqueueTaskOnExecutor(AsyncTask *task, ExecutorRef executor);
681681
/// Generally you should call swift_task_switch to switch execution
682682
/// synchronously when possible.
683683
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
684-
void swift_task_enqueue(Job *job, ExecutorRef executor);
684+
void swift_task_enqueue(Job *job, SerialExecutorRef executor);
685685

686686
/// Enqueue the given job to run asynchronously on the global
687687
/// execution pool.
@@ -716,7 +716,7 @@ bool swift_task_isOnExecutor(
716716
const SerialExecutorWitnessTable *wtable);
717717

718718
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
719-
bool swift_executor_isComplexEquality(ExecutorRef ref);
719+
bool swift_executor_isComplexEquality(SerialExecutorRef ref);
720720

721721
/// Return the 64bit TaskID (if the job is an AsyncTask),
722722
/// or the 32bits of the job Id otherwise.
@@ -886,27 +886,27 @@ void swift_task_asyncMainDrainQueue [[noreturn]]();
886886
/// Establish that the current thread is running as the given
887887
/// executor, then run a job.
888888
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
889-
void swift_job_run(Job *job, ExecutorRef executor);
889+
void swift_job_run(Job *job, SerialExecutorRef executor);
890890

891891
/// Return the current thread's active task reference.
892892
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
893893
AsyncTask *swift_task_getCurrent(void);
894894

895895
/// Return the current thread's active executor reference.
896896
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
897-
ExecutorRef swift_task_getCurrentExecutor(void);
897+
SerialExecutorRef swift_task_getCurrentExecutor(void);
898898

899899
/// Return the main-actor executor reference.
900900
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
901-
ExecutorRef swift_task_getMainExecutor(void);
901+
SerialExecutorRef swift_task_getMainExecutor(void);
902902

903903
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
904-
bool swift_task_isCurrentExecutor(ExecutorRef executor);
904+
bool swift_task_isCurrentExecutor(SerialExecutorRef executor);
905905

906906
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
907907
void swift_task_reportUnexpectedExecutor(
908908
const unsigned char *file, uintptr_t fileLength, bool fileIsASCII,
909-
uintptr_t line, ExecutorRef executor);
909+
uintptr_t line, SerialExecutorRef executor);
910910

911911
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
912912
JobPriority swift_task_getCurrentThreadPriority(void);

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2310,7 +2310,7 @@ FUNCTION(TaskCreate,
23102310

23112311
// void swift_task_switch(AsyncContext *resumeContext,
23122312
// TaskContinuationFunction *resumeFunction,
2313-
// ExecutorRef newExecutor);
2313+
// SerialExecutorRef newExecutor);
23142314
FUNCTION(TaskSwitchFunc,
23152315
swift_task_switch, SwiftAsyncCC,
23162316
ConcurrencyAvailability,
@@ -2372,7 +2372,7 @@ FUNCTION(ContinuationThrowingResumeWithError,
23722372
EFFECT(Concurrency),
23732373
UNKNOWN_MEMEFFECTS)
23742374

2375-
// ExecutorRef swift_task_getCurrentExecutor();
2375+
// SerialExecutorRef swift_task_getCurrentExecutor();
23762376
FUNCTION(TaskGetCurrentExecutor,
23772377
swift_task_getCurrentExecutor, SwiftCC,
23782378
ConcurrencyAvailability,
@@ -2382,7 +2382,7 @@ FUNCTION(TaskGetCurrentExecutor,
23822382
EFFECT(Concurrency),
23832383
MEMEFFECTS(ArgMemOnly))
23842384

2385-
// ExecutorRef swift_task_getMainExecutor();
2385+
// SerialExecutorRef swift_task_getMainExecutor();
23862386
FUNCTION(TaskGetMainExecutor,
23872387
swift_task_getMainExecutor, SwiftCC,
23882388
ConcurrencyAvailability,

0 commit comments

Comments
 (0)