Skip to content

Commit 3ed1112

Browse files
authored
Merge pull request #37325 from fredriss/async-task-id
[Concurrency] Add a unique Task ID to AsyncTask
2 parents bd010c3 + bbda706 commit 3ed1112

File tree

15 files changed

+67
-43
lines changed

15 files changed

+67
-43
lines changed

include/swift/ABI/MetadataValues.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2000,7 +2000,7 @@ enum class JobPriority : size_t {
20002000
};
20012001

20022002
/// Flags for schedulable jobs.
2003-
class JobFlags : public FlagSet<size_t> {
2003+
class JobFlags : public FlagSet<uint32_t> {
20042004
public:
20052005
enum {
20062006
Kind = 0,
@@ -2019,7 +2019,7 @@ class JobFlags : public FlagSet<size_t> {
20192019
Task_IsContinuingAsyncTask = 27,
20202020
};
20212021

2022-
explicit JobFlags(size_t bits) : FlagSet(bits) {}
2022+
explicit JobFlags(uint32_t bits) : FlagSet(bits) {}
20232023
JobFlags(JobKind kind) { setKind(kind); }
20242024
JobFlags(JobKind kind, JobPriority priority) {
20252025
setKind(kind);

include/swift/ABI/Task.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ class alignas(2 * alignof(void*)) Job :
6868

6969
JobFlags Flags;
7070

71+
// Derived classes can use this to store a Job Id.
72+
uint32_t Id = 0;
73+
7174
// We use this union to avoid having to do a second indirect branch
7275
// when resuming an asynchronous task, which we expect will be the
7376
// common case.
@@ -121,8 +124,13 @@ class alignas(2 * alignof(void*)) Job :
121124
};
122125

123126
// The compiler will eventually assume these.
127+
#if defined(__LP64__) || defined(_WIN64)
124128
static_assert(sizeof(Job) == 6 * sizeof(void*),
125129
"Job size is wrong");
130+
#else
131+
static_assert(sizeof(Job) == 8 * sizeof(void*),
132+
"Job size is wrong");
133+
#endif
126134
static_assert(alignof(Job) == 2 * alignof(void*),
127135
"Job alignment is wrong");
128136

@@ -229,6 +237,7 @@ class AsyncTask : public Job {
229237
Status(ActiveTaskStatus()),
230238
Local(TaskLocal::Storage()) {
231239
assert(flags.isAsyncTask());
240+
Id = getNextTaskId();
232241
}
233242

234243
/// Create a task with "immortal" reference counts.
@@ -242,6 +251,7 @@ class AsyncTask : public Job {
242251
Status(ActiveTaskStatus()),
243252
Local(TaskLocal::Storage()) {
244253
assert(flags.isAsyncTask());
254+
Id = getNextTaskId();
245255
}
246256

247257
~AsyncTask();
@@ -505,13 +515,24 @@ class AsyncTask : public Job {
505515
return reinterpret_cast<AsyncTask *&>(
506516
SchedulerPrivate[NextWaitingTaskIndex]);
507517
}
518+
519+
/// Get the next non-zero Task ID.
520+
uint32_t getNextTaskId() {
521+
static std::atomic<uint32_t> Id(1);
522+
uint32_t Next = Id.fetch_add(1, std::memory_order_relaxed);
523+
if (Next == 0) Next = Id.fetch_add(1, std::memory_order_relaxed);
524+
return Next;
525+
}
508526
};
509527

510528
// The compiler will eventually assume these.
511529
static_assert(sizeof(AsyncTask) == 14 * sizeof(void*),
512530
"AsyncTask size is wrong");
513531
static_assert(alignof(AsyncTask) == 2 * alignof(void*),
514532
"AsyncTask alignment is wrong");
533+
// Libc hardcodes this offset to extract the TaskID
534+
static_assert(offsetof(AsyncTask, Id) == 4 * sizeof(void *) + 4,
535+
"AsyncTask::Id offset is wrong");
515536

516537
inline void Job::runInFullyEstablishedContext() {
517538
if (auto task = dyn_cast<AsyncTask>(this))

include/swift/Runtime/Concurrency.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ 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(JobFlags flags,
41+
AsyncTaskAndContext swift_task_create_f(size_t flags,
4242
ThinNullaryAsyncSignature::FunctionType *function,
4343
size_t initialContextSize);
4444

@@ -51,7 +51,7 @@ using FutureAsyncSignature =
5151
/// closure.
5252
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
5353
AsyncTaskAndContext swift_task_create_future(
54-
JobFlags flags,
54+
size_t flags,
5555
const Metadata *futureResultType,
5656
void *closureEntryPoint,
5757
HeapObject * /* +1 */ closureContext);
@@ -60,7 +60,7 @@ AsyncTaskAndContext swift_task_create_future(
6060
/// function.
6161
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
6262
AsyncTaskAndContext swift_task_create_future_f(
63-
JobFlags flags,
63+
size_t flags,
6464
const Metadata *futureResultType,
6565
FutureAsyncSignature::FunctionType *function,
6666
size_t initialContextSize);
@@ -69,7 +69,7 @@ AsyncTaskAndContext swift_task_create_future_f(
6969
/// closure, and offer its result to the task group
7070
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
7171
AsyncTaskAndContext swift_task_create_group_future(
72-
JobFlags flags, TaskGroup *group,
72+
size_t flags, TaskGroup *group,
7373
const Metadata *futureResultType,
7474
void *closureEntryPoint,
7575
HeapObject * /* +1 */ closureContext);
@@ -78,7 +78,7 @@ AsyncTaskAndContext swift_task_create_group_future(
7878
/// function, and offer its result to the task group
7979
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
8080
AsyncTaskAndContext swift_task_create_group_future_f(
81-
JobFlags flags,
81+
size_t flags,
8282
TaskGroup *group,
8383
const Metadata *futureResultType,
8484
FutureAsyncSignature::FunctionType *function,

lib/IRGen/IRGenFunction.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -527,8 +527,8 @@ static llvm::Value *unsafeContinuationFromTask(IRGenFunction &IGF,
527527
static llvm::Value *emitLoadOfResumeContextFromTask(IRGenFunction &IGF,
528528
llvm::Value *task) {
529529
auto addr = Address(task, IGF.IGM.getPointerAlignment());
530-
auto resumeContextAddr =
531-
IGF.Builder.CreateStructGEP(addr, 5, 6 * IGF.IGM.getPointerSize());
530+
auto resumeContextAddr = IGF.Builder.CreateStructGEP(
531+
addr, 6, (5 * IGF.IGM.getPointerSize()) + Size(8));
532532
llvm::Value *resumeContext = IGF.Builder.CreateLoad(resumeContextAddr);
533533
if (auto &schema = IGF.getOptions().PointerAuth.TaskResumeContext) {
534534
auto info = PointerAuthInfo::emit(IGF, schema,

lib/IRGen/IRGenModule.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,8 @@ IRGenModule::IRGenModule(IRGenerator &irgen,
610610
SwiftTaskTy = createStructType(*this, "swift.task", {
611611
RefCountedStructTy, // object header
612612
Int8PtrTy, Int8PtrTy, // Job.SchedulerPrivate
613-
SizeTy, // Job.Flags
613+
Int32Ty, // Job.Flags
614+
Int32Ty, // Job.ID
614615
FunctionPtrTy, // Job.RunJob/Job.ResumeTask
615616
SwiftContextPtrTy, // Task.ResumeContext
616617
IntPtrTy // Task.Status
@@ -629,7 +630,8 @@ IRGenModule::IRGenModule(IRGenerator &irgen,
629630
SwiftJobTy = createStructType(*this, "swift.job", {
630631
RefCountedStructTy, // object header
631632
Int8PtrTy, Int8PtrTy, // SchedulerPrivate
632-
SizeTy, // flags
633+
Int32Ty, // flags
634+
Int32Ty, // ID
633635
FunctionPtrTy, // RunJob/ResumeTask
634636
});
635637
SwiftJobPtrTy = SwiftJobTy->getPointerTo(DefaultAS);

stdlib/public/CompatibilityOverride/CompatibilityOverrideConcurrency.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ OVERRIDE_ACTOR(task_switch, void,
9797
(resumeToContext, resumeFunction, newExecutor))
9898

9999
OVERRIDE_TASK(task_create_group_future_common, AsyncTaskAndContext, , , ,
100-
(JobFlags flags, TaskGroup *group,
100+
(size_t flags, TaskGroup *group,
101101
const Metadata *futureResultType,
102102
FutureAsyncSignature::FunctionType *function,
103103
void *closureContext, bool isAsyncLetTask,

stdlib/public/Concurrency/AsyncLet.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ static void swift_asyncLet_startImpl(AsyncLet *alet,
106106
flags.task_setIsChildTask(true);
107107

108108
auto childTaskAndContext = swift_task_create_async_let_future(
109-
flags,
109+
flags.getOpaqueValue(),
110110
futureResultType,
111111
closureEntryPoint,
112112
closureContext);

stdlib/public/Concurrency/Task.cpp

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -386,11 +386,12 @@ static void task_wait_throwing_resume_adapter(SWIFT_ASYNC_CONTEXT AsyncContext *
386386
/// Also, async-let tasks are not heap allcoated, but allcoated with the parent
387387
/// task's stack allocator.
388388
static AsyncTaskAndContext swift_task_create_group_future_commonImpl(
389-
JobFlags flags, TaskGroup *group,
389+
size_t rawFlags, TaskGroup *group,
390390
const Metadata *futureResultType,
391391
FutureAsyncSignature::FunctionType *function,
392392
void *closureContext, bool isAsyncLetTask,
393393
size_t initialContextSize) {
394+
JobFlags flags(rawFlags);
394395
assert((futureResultType != nullptr) == flags.task_isFuture());
395396
assert(!flags.task_isFuture() ||
396397
initialContextSize >= sizeof(FutureAsyncContext));
@@ -568,32 +569,32 @@ static AsyncTaskAndContext swift_task_create_group_future_commonImpl(
568569
}
569570

570571
static AsyncTaskAndContext swift_task_create_group_future_common(
571-
JobFlags flags, TaskGroup *group, const Metadata *futureResultType,
572+
size_t flags, TaskGroup *group, const Metadata *futureResultType,
572573
FutureAsyncSignature::FunctionType *function,
573574
void *closureContext, bool isAsyncLetTask,
574575
size_t initialContextSize);
575576

576577
AsyncTaskAndContext
577-
swift::swift_task_create_f(JobFlags flags,
578+
swift::swift_task_create_f(size_t flags,
578579
ThinNullaryAsyncSignature::FunctionType *function,
579580
size_t initialContextSize) {
580581
return swift_task_create_future_f(
581582
flags, nullptr, function, initialContextSize);
582583
}
583584

584585
AsyncTaskAndContext swift::swift_task_create_future_f(
585-
JobFlags flags,
586+
size_t flags,
586587
const Metadata *futureResultType,
587588
FutureAsyncSignature::FunctionType *function, size_t initialContextSize) {
588-
assert(!flags.task_isGroupChildTask() &&
589+
assert(!JobFlags(flags).task_isGroupChildTask() &&
589590
"use swift_task_create_group_future_f to initialize task group child tasks");
590591
return swift_task_create_group_future_f(
591592
flags, /*group=*/nullptr, futureResultType,
592593
function, initialContextSize);
593594
}
594595

595596
AsyncTaskAndContext swift::swift_task_create_group_future_f(
596-
JobFlags flags, TaskGroup *group,
597+
size_t flags, TaskGroup *group,
597598
const Metadata *futureResultType,
598599
FutureAsyncSignature::FunctionType *function,
599600
size_t initialContextSize) {
@@ -621,7 +622,7 @@ getAsyncClosureEntryPointAndContextSize(void *function,
621622
fnPtr->ExpectedContextSize};
622623
}
623624

624-
AsyncTaskAndContext swift::swift_task_create_future(JobFlags flags,
625+
AsyncTaskAndContext swift::swift_task_create_future(size_t flags,
625626
const Metadata *futureResultType,
626627
void *closureEntry,
627628
HeapObject * /* +1 */ closureContext) {
@@ -640,7 +641,7 @@ AsyncTaskAndContext swift::swift_task_create_future(JobFlags flags,
640641
initialContextSize);
641642
}
642643

643-
AsyncTaskAndContext swift::swift_task_create_async_let_future(JobFlags flags,
644+
AsyncTaskAndContext swift::swift_task_create_async_let_future(size_t flags,
644645
const Metadata *futureResultType,
645646
void *closureEntry,
646647
void *closureContext) {
@@ -661,7 +662,7 @@ AsyncTaskAndContext swift::swift_task_create_async_let_future(JobFlags flags,
661662

662663
AsyncTaskAndContext
663664
swift::swift_task_create_group_future(
664-
JobFlags flags, TaskGroup *group,
665+
size_t flags, TaskGroup *group,
665666
const Metadata *futureResultType,
666667
void *closureEntry,
667668
HeapObject * /*+1*/closureContext) {
@@ -853,7 +854,7 @@ void swift::swift_task_runAndBlockThread(const void *function,
853854
// Set up a task that runs the runAndBlock async function above.
854855
auto flags = JobFlags(JobKind::Task, JobPriority::Default);
855856
auto pair = swift_task_create_f(
856-
flags,
857+
flags.getOpaqueValue(),
857858
reinterpret_cast<ThinNullaryAsyncSignature::FunctionType *>(
858859
&runAndBlock_start),
859860
sizeof(RunAndBlockContext));

stdlib/public/Concurrency/Task.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -253,12 +253,12 @@ extension Task {
253253
/// This is a port of the C++ FlagSet.
254254
struct JobFlags {
255255
/// Kinds of schedulable jobs.
256-
enum Kind: Int {
256+
enum Kind: Int32 {
257257
case task = 0
258258
}
259259

260260
/// The actual bit representation of these flags.
261-
var bits: Int = 0
261+
var bits: Int32 = 0
262262

263263
/// The kind of job described by these flags.
264264
var kind: Kind {
@@ -277,11 +277,11 @@ extension Task {
277277
/// The priority given to the job.
278278
var priority: Priority? {
279279
get {
280-
Priority(rawValue: (bits & 0xFF00) >> 8)
280+
Priority(rawValue: (Int(bits) & 0xFF00) >> 8)
281281
}
282282

283283
set {
284-
bits = (bits & ~0xFF00) | ((newValue?.rawValue ?? 0) << 8)
284+
bits = (bits & ~0xFF00) | Int32((newValue?.rawValue ?? 0) << 8)
285285
}
286286
}
287287

@@ -410,7 +410,7 @@ public func detach<T>(
410410
flags.isFuture = true
411411

412412
// Create the asynchronous task future.
413-
let (task, _) = Builtin.createAsyncTaskFuture(flags.bits, operation)
413+
let (task, _) = Builtin.createAsyncTaskFuture(Int(flags.bits), operation)
414414

415415
// Enqueue the resulting job.
416416
_enqueueJobGlobal(Builtin.convertTaskToJob(task))
@@ -463,7 +463,7 @@ public func detach<T>(
463463
flags.isFuture = true
464464

465465
// Create the asynchronous task future.
466-
let (task, _) = Builtin.createAsyncTaskFuture(flags.bits, operation)
466+
let (task, _) = Builtin.createAsyncTaskFuture(Int(flags.bits), operation)
467467

468468
// Enqueue the resulting job.
469469
_enqueueJobGlobal(Builtin.convertTaskToJob(task))
@@ -533,7 +533,7 @@ public func async<T>(
533533
flags.isContinuingAsyncTask = true
534534

535535
// Create the asynchronous task future.
536-
let (task, _) = Builtin.createAsyncTaskFuture(flags.bits, operation)
536+
let (task, _) = Builtin.createAsyncTaskFuture(Int(flags.bits), operation)
537537

538538
// Copy all task locals to the newly created task.
539539
// We must copy them rather than point to the current task since the new task
@@ -578,7 +578,7 @@ public func async<T>(
578578
flags.isContinuingAsyncTask = true
579579

580580
// Create the asynchronous task future.
581-
let (task, _) = Builtin.createAsyncTaskFuture(flags.bits, operation)
581+
let (task, _) = Builtin.createAsyncTaskFuture(Int(flags.bits), operation)
582582

583583
// Enqueue the resulting job.
584584
_enqueueJobGlobal(Builtin.convertTaskToJob(task))

stdlib/public/Concurrency/TaskGroup.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ public struct TaskGroup<ChildTaskResult> {
269269

270270
// Create the asynchronous task future.
271271
let (childTask, _) = Builtin.createAsyncTaskGroupFuture(
272-
flags.bits, _group, operation)
272+
Int(flags.bits), _group, operation)
273273

274274
// Attach it to the group's task record in the current task.
275275
_taskGroupAttachChild(group: _group, child: childTask)
@@ -332,7 +332,7 @@ public struct TaskGroup<ChildTaskResult> {
332332

333333
// Create the asynchronous task future.
334334
let (childTask, _) = Builtin.createAsyncTaskGroupFuture(
335-
flags.bits, _group, operation)
335+
Int(flags.bits), _group, operation)
336336

337337
// Attach it to the group's task record in the current task.
338338
_taskGroupAttachChild(group: _group, child: childTask)
@@ -558,7 +558,7 @@ public struct ThrowingTaskGroup<ChildTaskResult, Failure: Error> {
558558

559559
// Create the asynchronous task future.
560560
let (childTask, _) = Builtin.createAsyncTaskGroupFuture(
561-
flags.bits, _group, operation)
561+
Int(flags.bits), _group, operation)
562562

563563
// Attach it to the group's task record in the current task.
564564
_taskGroupAttachChild(group: _group, child: childTask)
@@ -621,7 +621,7 @@ public struct ThrowingTaskGroup<ChildTaskResult, Failure: Error> {
621621

622622
// Create the asynchronous task future.
623623
let (childTask, _) = Builtin.createAsyncTaskGroupFuture(
624-
flags.bits, _group, operation)
624+
Int(flags.bits), _group, operation)
625625

626626
// Attach it to the group's task record in the current task.
627627
_taskGroupAttachChild(group: _group, child: childTask)

stdlib/public/Concurrency/TaskPrivate.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ void runJobInEstablishedExecutorContext(Job *job);
5959
/// Clear the active task reference for the current thread.
6060
AsyncTask *_swift_task_clearCurrent();
6161

62-
AsyncTaskAndContext swift_task_create_async_let_future(JobFlags flags,
62+
AsyncTaskAndContext swift_task_create_async_let_future(size_t flags,
6363
const Metadata *futureResultType,
6464
void *closureEntry,
6565
void *closureContext);

test/IRGen/async/builtins.sil

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ bb0(%0 : $Int, %1: @guaranteed $@async @callee_owned @substituted <τ_0_0> () ->
6363
sil hidden [ossa] @resume_nonthrowing_continuation : $(@in Builtin.NativeObject, Builtin.RawUnsafeContinuation) -> () {
6464
bb0(%0 : $*Builtin.NativeObject, %1 : $Builtin.RawUnsafeContinuation):
6565
// CHECK: [[CONT:%.*]] = bitcast i8* %1 to %swift.task*
66-
// CHECK-NEXT: [[CONTEXT_SLOT:%.*]] = getelementptr inbounds %swift.task, %swift.task* [[CONT]], i32 0, i32 5
66+
// CHECK-NEXT: [[CONTEXT_SLOT:%.*]] = getelementptr inbounds %swift.task, %swift.task* [[CONT]], i32 0, i32 6
6767
// CHECK-NEXT: [[CONTEXT_OPAQUE:%.*]] = load %swift.context*, %swift.context** [[CONTEXT_SLOT]], align
6868
// CHECK-NEXT: [[CONTEXT:%.*]] = bitcast %swift.context* [[CONTEXT_OPAQUE]] to %swift.continuation_context*
6969
// CHECK-NEXT: [[RESULT_ADDR_SLOT:%.*]] = getelementptr inbounds %swift.continuation_context, %swift.continuation_context* [[CONTEXT]], i32 0, i32 3
@@ -82,7 +82,7 @@ bb0(%0 : $*Builtin.NativeObject, %1 : $Builtin.RawUnsafeContinuation):
8282
sil hidden [ossa] @resume_throwing_continuation : $(@in Builtin.NativeObject, Builtin.RawUnsafeContinuation) -> () {
8383
bb0(%0 : $*Builtin.NativeObject, %1 : $Builtin.RawUnsafeContinuation):
8484
// CHECK: [[CONT:%.*]] = bitcast i8* %1 to %swift.task*
85-
// CHECK-NEXT: [[CONTEXT_SLOT:%.*]] = getelementptr inbounds %swift.task, %swift.task* [[CONT]], i32 0, i32 5
85+
// CHECK-NEXT: [[CONTEXT_SLOT:%.*]] = getelementptr inbounds %swift.task, %swift.task* [[CONT]], i32 0, i32 6
8686
// CHECK-NEXT: [[CONTEXT_OPAQUE:%.*]] = load %swift.context*, %swift.context** [[CONTEXT_SLOT]], align
8787
// CHECK-NEXT: [[CONTEXT:%.*]] = bitcast %swift.context* [[CONTEXT_OPAQUE]] to %swift.continuation_context*
8888
// CHECK-NEXT: [[RESULT_ADDR_SLOT:%.*]] = getelementptr inbounds %swift.continuation_context, %swift.continuation_context* [[CONTEXT]], i32 0, i32 3

0 commit comments

Comments
 (0)