2727
2828#include " swift/ABI/Enum.h"
2929#include " swift/ABI/ObjectFile.h"
30+ #include " swift/Concurrency/Actor.h"
3031#include " swift/Remote/MemoryReader.h"
3132#include " swift/Remote/MetadataReader.h"
3233#include " swift/Reflection/Records.h"
5859// with escalation | present | full
5960// with escalation | not present | DEGRADED
6061//
61- // Currently, degraded info means that IsRunning is not available (indicated
62- // with `HasIsRunning = false`) and async backtraces are not provided.
62+ // Currently, degraded info has these effects:
63+ // 1. Task.IsRunning is not available, indicated with Task.HasIsRunning = false.
64+ // 2. Task async backtraces are not provided.
65+ // 3. Task and actor thread ports are not available, indicated with
66+ // HasThreadPort = false.
6367
6468#if __has_include(<dispatch/swift_concurrency_private.h>)
6569#include < dispatch/swift_concurrency_private.h>
@@ -185,6 +189,9 @@ class ReflectionContext
185189 bool IsRunning;
186190 bool IsEnqueued;
187191
192+ bool HasThreadPort;
193+ uint32_t ThreadPort;
194+
188195 uint64_t Id;
189196 StoredPointer RunJob;
190197 StoredPointer AllocatorSlabPtr;
@@ -193,8 +200,15 @@ class ReflectionContext
193200 };
194201
195202 struct ActorInfo {
196- StoredSize Flags;
197203 StoredPointer FirstJob;
204+
205+ uint8_t State;
206+ bool IsDistributedRemote;
207+ bool IsPriorityEscalated;
208+ uint8_t MaxPriority;
209+
210+ bool HasThreadPort;
211+ uint32_t ThreadPort;
198212 };
199213
200214 explicit ReflectionContext (std::shared_ptr<MemoryReader> reader)
@@ -1532,6 +1546,44 @@ class ReflectionContext
15321546 Task->PrivateStorage .Status .Flags [0 ] & ActiveTaskStatusFlags::IsRunning;
15331547 }
15341548
1549+ std::pair<bool , uint32_t > getThreadPort (
1550+ const AsyncTask<Runtime, ActiveTaskStatusWithEscalation<Runtime>> *Task) {
1551+ #if HAS_DISPATCH_LOCK_IS_LOCKED
1552+ return {true ,
1553+ dispatch_lock_owner (Task->PrivateStorage .Status .ExecutionLock [0 ])};
1554+ #else
1555+ // The target runtime was built with priority escalation but we don't have
1556+ // the swift_concurrency_private.h header needed to decode the lock.
1557+ return {false , 0 };
1558+ #endif
1559+ }
1560+
1561+ std::pair<bool , uint32_t > getThreadPort (
1562+ const AsyncTask<Runtime, ActiveTaskStatusWithoutEscalation<Runtime>>
1563+ *Task) {
1564+ // Tasks without escalation have no thread port to query.
1565+ return {false , 0 };
1566+ }
1567+
1568+ std::pair<bool , uint32_t > getThreadPort (
1569+ const DefaultActorImpl<Runtime, ActiveActorStatusWithEscalation<Runtime>>
1570+ *Actor) {
1571+ #if HAS_DISPATCH_LOCK_IS_LOCKED
1572+ return {true , dispatch_lock_owner (Actor->Status .DrainLock [0 ])};
1573+ #else
1574+ // The target runtime was built with priority escalation but we don't have
1575+ // the swift_concurrency_private.h header needed to decode the lock.
1576+ return {false , 0 };
1577+ #endif
1578+ }
1579+
1580+ std::pair<bool , uint32_t >
1581+ getThreadPort (const DefaultActorImpl<
1582+ Runtime, ActiveActorStatusWithoutEscalation<Runtime>> *Actor) {
1583+ // Actors without escalation have no thread port to query.
1584+ return {false , 0 };
1585+ }
1586+
15351587 template <typename AsyncTaskType>
15361588 std::pair<llvm::Optional<std::string>, AsyncTaskInfo>
15371589 asyncTaskInfo (StoredPointer AsyncTaskPtr) {
@@ -1557,6 +1609,8 @@ class ReflectionContext
15571609 Info.IsEnqueued = TaskStatusFlags & ActiveTaskStatusFlags::IsEnqueued;
15581610
15591611 setIsRunning (Info, AsyncTaskObj.get ());
1612+ std::tie (Info.HasThreadPort , Info.ThreadPort ) =
1613+ getThreadPort (AsyncTaskObj.get ());
15601614
15611615 Info.Id =
15621616 AsyncTaskObj->Id | ((uint64_t )AsyncTaskObj->PrivateStorage .Id << 32 );
@@ -1626,15 +1680,26 @@ class ReflectionContext
16261680 return {std::string (" failure reading actor" ), {}};
16271681
16281682 ActorInfo Info{};
1629- Info.Flags = ActorObj->Status .Flags [0 ];
16301683
1631- // Status is the low 3 bits of Flags. Status of 0 is Idle. Don't read
1632- // FirstJob when idle.
1633- auto Status = Info.Flags & 0x7 ;
1634- if (Status != 0 ) {
1684+ uint32_t Flags = ActorObj->Status .Flags [0 ];
1685+ Info.State = Flags & concurrency::ActorFlagConstants::ActorStateMask;
1686+ Info.IsDistributedRemote =
1687+ Flags & concurrency::ActorFlagConstants::DistributedRemote;
1688+ Info.IsPriorityEscalated =
1689+ Flags & concurrency::ActorFlagConstants::IsPriorityEscalated;
1690+ Info.MaxPriority =
1691+ (Flags & concurrency::ActorFlagConstants::PriorityMask) >>
1692+ concurrency::ActorFlagConstants::PriorityShift;
1693+
1694+ // Don't read FirstJob when idle.
1695+ if (Info.State != concurrency::ActorFlagConstants::Idle) {
16351696 // This is a JobRef which stores flags in the low bits.
16361697 Info.FirstJob = ActorObj->Status .FirstJob & ~StoredPointer (0x3 );
16371698 }
1699+
1700+ std::tie (Info.HasThreadPort , Info.ThreadPort ) =
1701+ getThreadPort (ActorObj.get ());
1702+
16381703 return {llvm::None, Info};
16391704 }
16401705
0 commit comments