43
43
44
44
#include < inttypes.h>
45
45
46
+ // The Swift runtime can be built in two ways: with or without
47
+ // SWIFT_CONCURRENCY_ENABLE_PRIORITY_ESCALATION enabled. In order to decode the
48
+ // lock used in a runtime with priority escalation enabled, we need inline
49
+ // functions from dispatch/swift_concurrency_private.h. If we don't have that
50
+ // header at build time, we can still build but we'll be unable to decode the
51
+ // lock and thus information about a running task is degraded. There are four
52
+ // combinations:
53
+ //
54
+ // Runtime | swift_concurrency_private.h | task running info
55
+ // --------------------+-----------------------------+------------------
56
+ // without escalation | present | full
57
+ // without escalation | not present | full
58
+ // with escalation | present | full
59
+ // with escalation | not present | DEGRADED
60
+ //
61
+ // Currently, degraded info means that IsRunning is not available (indicated
62
+ // with `HasIsRunning = false`) and async backtraces are not provided.
63
+
64
+ #if __has_include(<dispatch/swift_concurrency_private.h>)
65
+ #include < dispatch/swift_concurrency_private.h>
66
+ #define HAS_DISPATCH_LOCK_IS_LOCKED 1
67
+ #endif
68
+
46
69
namespace {
47
70
48
71
template <unsigned PointerSize> struct MachOTraits ;
@@ -145,8 +168,23 @@ class ReflectionContext
145
168
};
146
169
147
170
struct AsyncTaskInfo {
148
- uint32_t JobFlags;
149
- uint64_t TaskStatusFlags;
171
+ // Job flags.
172
+ unsigned Kind;
173
+ unsigned EnqueuePriority;
174
+ bool IsChildTask;
175
+ bool IsFuture;
176
+ bool IsGroupChildTask;
177
+ bool IsAsyncLetTask;
178
+
179
+ // Task flags.
180
+ unsigned MaxPriority;
181
+ bool IsCancelled;
182
+ bool IsStatusRecordLocked;
183
+ bool IsEscalated;
184
+ bool HasIsRunning; // If false, the IsRunning flag is not valid.
185
+ bool IsRunning;
186
+ bool IsEnqueued;
187
+
150
188
uint64_t Id;
151
189
StoredPointer RunJob;
152
190
StoredPointer AllocatorSlabPtr;
@@ -1435,18 +1473,91 @@ class ReflectionContext
1435
1473
asyncTaskInfo (StoredPointer AsyncTaskPtr) {
1436
1474
loadTargetPointers ();
1437
1475
1438
- if (supportsPriorityEscalation) {
1439
- return {std::string (" Failure reading async task with escalation support" ), {}};
1440
- }
1476
+ if (supportsPriorityEscalation)
1477
+ return asyncTaskInfo<
1478
+ AsyncTask<Runtime, ActiveTaskStatusWithEscalation<Runtime>>>(
1479
+ AsyncTaskPtr);
1480
+ else
1481
+ return asyncTaskInfo<
1482
+ AsyncTask<Runtime, ActiveTaskStatusWithoutEscalation<Runtime>>>(
1483
+ AsyncTaskPtr);
1484
+ }
1485
+
1486
+ std::pair<llvm::Optional<std::string>, ActorInfo>
1487
+ actorInfo (StoredPointer ActorPtr) {
1488
+ if (supportsPriorityEscalation)
1489
+ return actorInfo<
1490
+ DefaultActorImpl<Runtime, ActiveActorStatusWithEscalation<Runtime>>>(
1491
+ ActorPtr);
1492
+ else
1493
+ return actorInfo<DefaultActorImpl<
1494
+ Runtime, ActiveActorStatusWithoutEscalation<Runtime>>>(ActorPtr);
1495
+ }
1496
+
1497
+ StoredPointer nextJob (StoredPointer JobPtr) {
1498
+ using Job = Job<Runtime>;
1499
+
1500
+ auto JobBytes = getReader ().readBytes (RemoteAddress (JobPtr), sizeof (Job));
1501
+ auto *JobObj = reinterpret_cast <const Job *>(JobBytes.get ());
1502
+ if (!JobObj)
1503
+ return 0 ;
1504
+
1505
+ // This is a JobRef which stores flags in the low bits.
1506
+ return JobObj->SchedulerPrivate [0 ] & ~StoredPointer (0x3 );
1507
+ }
1508
+
1509
+ private:
1510
+ void setIsRunning (
1511
+ AsyncTaskInfo &Info,
1512
+ const AsyncTask<Runtime, ActiveTaskStatusWithEscalation<Runtime>> *Task) {
1513
+ #if HAS_DISPATCH_LOCK_IS_LOCKED
1514
+ Info.HasIsRunning = true ;
1515
+ Info.IsRunning =
1516
+ dispatch_lock_is_locked (Task->PrivateStorage .Status .ExecutionLock [0 ]);
1517
+ #else
1518
+ // The target runtime was built with priority escalation but we don't have
1519
+ // the swift_concurrency_private.h header needed to decode the running
1520
+ // status in the task. Set HasIsRunning to false to indicate that we can't
1521
+ // tell whether or not the task is running.
1522
+ Info.HasIsRunning = false ;
1523
+ #endif
1524
+ }
1525
+
1526
+ void setIsRunning (
1527
+ AsyncTaskInfo &Info,
1528
+ const AsyncTask<Runtime, ActiveTaskStatusWithoutEscalation<Runtime>>
1529
+ *Task) {
1530
+ Info.HasIsRunning = true ;
1531
+ Info.IsRunning =
1532
+ Task->PrivateStorage .Status .Flags [0 ] & ActiveTaskStatusFlags::IsRunning;
1533
+ }
1441
1534
1442
- using AsyncTask = AsyncTask<Runtime, ActiveTaskStatusWithoutEscalation<Runtime>>;
1443
- auto AsyncTaskObj = readObj<AsyncTask>(AsyncTaskPtr);
1535
+ template <typename AsyncTaskType>
1536
+ std::pair<llvm::Optional<std::string>, AsyncTaskInfo>
1537
+ asyncTaskInfo (StoredPointer AsyncTaskPtr) {
1538
+ auto AsyncTaskObj = readObj<AsyncTaskType>(AsyncTaskPtr);
1444
1539
if (!AsyncTaskObj)
1445
1540
return {std::string (" failure reading async task" ), {}};
1446
1541
1447
1542
AsyncTaskInfo Info{};
1448
- Info.JobFlags = AsyncTaskObj->Flags ;
1449
- Info.TaskStatusFlags = AsyncTaskObj->PrivateStorage .Status .Flags [0 ];
1543
+
1544
+ swift::JobFlags JobFlags (AsyncTaskObj->Flags );
1545
+ Info.Kind = static_cast <unsigned >(JobFlags.getKind ());
1546
+ Info.EnqueuePriority = static_cast <unsigned >(JobFlags.getPriority ());
1547
+ Info.IsChildTask = JobFlags.task_isChildTask ();
1548
+ Info.IsFuture = JobFlags.task_isFuture ();
1549
+ Info.IsGroupChildTask = JobFlags.task_isGroupChildTask ();
1550
+ Info.IsAsyncLetTask = JobFlags.task_isAsyncLetTask ();
1551
+
1552
+ uint32_t TaskStatusFlags = AsyncTaskObj->PrivateStorage .Status .Flags [0 ];
1553
+ Info.IsCancelled = TaskStatusFlags & ActiveTaskStatusFlags::IsCancelled;
1554
+ Info.IsStatusRecordLocked =
1555
+ TaskStatusFlags & ActiveTaskStatusFlags::IsStatusRecordLocked;
1556
+ Info.IsEscalated = TaskStatusFlags & ActiveTaskStatusFlags::IsEscalated;
1557
+ Info.IsEnqueued = TaskStatusFlags & ActiveTaskStatusFlags::IsEnqueued;
1558
+
1559
+ setIsRunning (Info, AsyncTaskObj.get ());
1560
+
1450
1561
Info.Id =
1451
1562
AsyncTaskObj->Id | ((uint64_t )AsyncTaskObj->PrivateStorage .Id << 32 );
1452
1563
Info.AllocatorSlabPtr = AsyncTaskObj->PrivateStorage .Allocator .FirstSlab ;
@@ -1479,8 +1590,7 @@ class ReflectionContext
1479
1590
while (ChildTask) {
1480
1591
Info.ChildTasks .push_back (ChildTask);
1481
1592
1482
- StoredPointer ChildFragmentAddr =
1483
- ChildTask + sizeof (AsyncTask);
1593
+ StoredPointer ChildFragmentAddr = ChildTask + sizeof (*AsyncTaskObj);
1484
1594
auto ChildFragmentObj =
1485
1595
readObj<ChildFragment<Runtime>>(ChildFragmentAddr);
1486
1596
if (ChildFragmentObj)
@@ -1492,13 +1602,8 @@ class ReflectionContext
1492
1602
RecordPtr = RecordObj->Parent ;
1493
1603
}
1494
1604
1495
- // Walk the async backtrace if the task isn't running or cancelled.
1496
- // TODO: Use isEnqueued from https://github.com/apple/swift/pull/41088/ once
1497
- // that's available.
1498
- int IsCancelledFlag = 0x100 ;
1499
- int IsRunningFlag = 0x800 ;
1500
- if (!(AsyncTaskObj->PrivateStorage .Status .Flags [0 ] & IsCancelledFlag) &&
1501
- !(AsyncTaskObj->PrivateStorage .Status .Flags [0 ] & IsRunningFlag)) {
1605
+ // Walk the async backtrace.
1606
+ if (Info.HasIsRunning && !Info.IsRunning ) {
1502
1607
auto ResumeContext = AsyncTaskObj->ResumeContextAndReserved [0 ];
1503
1608
while (ResumeContext) {
1504
1609
auto ResumeContextObj = readObj<AsyncContext<Runtime>>(ResumeContext);
@@ -1513,15 +1618,10 @@ class ReflectionContext
1513
1618
return {llvm::None, Info};
1514
1619
}
1515
1620
1621
+ template <typename ActorType>
1516
1622
std::pair<llvm::Optional<std::string>, ActorInfo>
1517
1623
actorInfo (StoredPointer ActorPtr) {
1518
- if (supportsPriorityEscalation) {
1519
- return {std::string (" Failure reading actor with escalation support" ), {}};
1520
- }
1521
-
1522
- using DefaultActorImpl = DefaultActorImpl<Runtime, ActiveActorStatusWithoutEscalation<Runtime>>;
1523
-
1524
- auto ActorObj = readObj<DefaultActorImpl>(ActorPtr);
1624
+ auto ActorObj = readObj<ActorType>(ActorPtr);
1525
1625
if (!ActorObj)
1526
1626
return {std::string (" failure reading actor" ), {}};
1527
1627
@@ -1538,22 +1638,10 @@ class ReflectionContext
1538
1638
return {llvm::None, Info};
1539
1639
}
1540
1640
1541
- StoredPointer nextJob (StoredPointer JobPtr) {
1542
- using Job = Job<Runtime>;
1543
-
1544
- auto JobBytes = getReader ().readBytes (RemoteAddress (JobPtr), sizeof (Job));
1545
- auto *JobObj = reinterpret_cast <const Job *>(JobBytes.get ());
1546
- if (!JobObj)
1547
- return 0 ;
1548
-
1549
- // This is a JobRef which stores flags in the low bits.
1550
- return JobObj->SchedulerPrivate [0 ] & ~StoredPointer (0x3 );
1551
- }
1552
-
1553
- private:
1554
1641
// Get the most human meaningful "run job" function pointer from the task,
1555
1642
// like AsyncTask::getResumeFunctionForLogging does.
1556
- StoredPointer getRunJob (const AsyncTask<Runtime, ActiveTaskStatusWithoutEscalation<Runtime>> *AsyncTaskObj) {
1643
+ template <typename AsyncTaskType>
1644
+ StoredPointer getRunJob (const AsyncTaskType *AsyncTaskObj) {
1557
1645
auto Fptr = stripSignedPointer (AsyncTaskObj->RunJob );
1558
1646
1559
1647
loadTargetPointers ();
@@ -1612,9 +1700,11 @@ class ReflectionContext
1612
1700
getFunc (" _swift_concurrency_debug_task_wait_throwing_resume_adapter" );
1613
1701
target_task_future_wait_resume_adapter =
1614
1702
getFunc (" _swift_concurrency_debug_task_future_wait_resume_adapter" );
1615
- auto supportsPriorityEscalationAddr = getReader ().getSymbolAddress (" _swift_concurrency_debug_supportsPriorityEscalation" );
1703
+ auto supportsPriorityEscalationAddr = getReader ().getSymbolAddress (
1704
+ " _swift_concurrency_debug_supportsPriorityEscalation" );
1616
1705
if (supportsPriorityEscalationAddr) {
1617
- getReader ().readInteger (supportsPriorityEscalationAddr, &supportsPriorityEscalation);
1706
+ getReader ().readInteger (supportsPriorityEscalationAddr,
1707
+ &supportsPriorityEscalation);
1618
1708
}
1619
1709
1620
1710
setupTargetPointers = true ;
0 commit comments