Skip to content

Commit fe09ad6

Browse files
committed
Add placeholder for getting thread data
1 parent 786d008 commit fe09ad6

File tree

8 files changed

+122
-8
lines changed

8 files changed

+122
-8
lines changed

docs/design/datacontracts/Thread.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ ThreadData GetThreadData(TargetPointer threadPointer)
159159
AllocContextLimit : thread.m_alloc_context.alloc_limit,
160160
Frame : thread.m_pFrame,
161161
TEB : thread.Has_m_pTEB ? thread.m_pTEB : TargetPointer.Null,
162-
LastThreadObjectHandle : new DacGCHandle(thread.m_LastThrownObjectHandle),
162+
LastThrownObjectHandle : new DacGCHandle(thread.m_LastThrownObjectHandle),
163163
FirstNestedException : firstNestedException,
164164
NextThread : ThreadListReader.GetHead.GetNext(threadPointer)
165165
);

src/coreclr/debug/daccess/dacimpl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1229,6 +1229,7 @@ class ClrDataAccess
12291229

12301230
HRESULT Initialize(void);
12311231

1232+
HRESULT GetThreadDataImpl(CLRDATA_ADDRESS threadAddr, struct DacpThreadData *threadData);
12321233
HRESULT GetThreadStoreDataImpl(struct DacpThreadStoreData *data);
12331234

12341235
BOOL IsExceptionFromManagedCode(EXCEPTION_RECORD * pExceptionRecord);

src/coreclr/debug/daccess/request.cpp

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -761,11 +761,52 @@ ClrDataAccess::GetHeapAllocData(unsigned int count, struct DacpGenerationAllocDa
761761
return hr;
762762
}
763763

764-
HRESULT
765-
ClrDataAccess::GetThreadData(CLRDATA_ADDRESS threadAddr, struct DacpThreadData *threadData)
764+
HRESULT ClrDataAccess::GetThreadData(CLRDATA_ADDRESS threadAddr, struct DacpThreadData* threadData)
766765
{
767766
SOSDacEnter();
768767

768+
if (m_cdacSos != NULL)
769+
{
770+
hr = m_cdacSos->GetThreadData(threadAddr, threadData);
771+
if (FAILED(hr))
772+
{
773+
hr = GetThreadDataImpl(threadAddr, threadData);
774+
}
775+
#ifdef _DEBUG
776+
else
777+
{
778+
DacpThreadData threadDataLocal;
779+
HRESULT hrLocal = GetThreadDataImpl(threadAddr, &threadDataLocal);
780+
_ASSERTE(hr == hrLocal);
781+
_ASSERTE(threadData->corThreadId == threadDataLocal.corThreadId);
782+
_ASSERTE(threadData->osThreadId == threadDataLocal.osThreadId);
783+
_ASSERTE(threadData->state == threadDataLocal.state);
784+
_ASSERTE(threadData->preemptiveGCDisabled == threadDataLocal.preemptiveGCDisabled);
785+
_ASSERTE(threadData->allocContextPtr == threadDataLocal.allocContextPtr);
786+
_ASSERTE(threadData->allocContextLimit == threadDataLocal.allocContextLimit);
787+
_ASSERTE(threadData->context == threadDataLocal.context);
788+
_ASSERTE(threadData->domain == threadDataLocal.domain);
789+
_ASSERTE(threadData->pFrame == threadDataLocal.pFrame);
790+
_ASSERTE(threadData->lockCount == threadDataLocal.lockCount);
791+
_ASSERTE(threadData->firstNestedException == threadDataLocal.firstNestedException);
792+
_ASSERTE(threadData->teb == threadDataLocal.teb);
793+
_ASSERTE(threadData->fiberData == threadDataLocal.fiberData);
794+
_ASSERTE(threadData->lastThrownObjectHandle == threadDataLocal.lastThrownObjectHandle);
795+
_ASSERTE(threadData->nextThread == threadDataLocal.nextThread);;
796+
}
797+
#endif
798+
}
799+
else
800+
{
801+
hr = GetThreadDataImpl(threadAddr, threadData);
802+
}
803+
804+
SOSDacLeave();
805+
return hr;
806+
}
807+
808+
HRESULT ClrDataAccess::GetThreadDataImpl(CLRDATA_ADDRESS threadAddr, struct DacpThreadData *threadData)
809+
{
769810
// marshal the Thread object from the target
770811
Thread* thread = PTR_Thread(TO_TADDR(threadAddr));
771812

@@ -804,8 +845,7 @@ ClrDataAccess::GetThreadData(CLRDATA_ADDRESS threadAddr, struct DacpThreadData *
804845
thread->m_ExceptionState.m_currentExInfo.m_pPrevNestedInfo);
805846
#endif // FEATURE_EH_FUNCLETS
806847

807-
SOSDacLeave();
808-
return hr;
848+
return S_OK;
809849
}
810850

811851
#ifdef FEATURE_REJIT

src/coreclr/debug/runtimeinfo/datadescriptor.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,10 @@ CDAC_TYPES_BEGIN()
105105

106106
CDAC_TYPE_BEGIN(Thread)
107107
CDAC_TYPE_INDETERMINATE(Thread)
108+
CDAC_TYPE_FIELD(Thread, /*uint32*/, Id, cdac_offsets<Thread>::Id)
109+
CDAC_TYPE_FIELD(Thread, /*nuint*/, OSId, cdac_offsets<Thread>::OSId)
108110
CDAC_TYPE_FIELD(Thread, GCHandle, GCHandle, cdac_offsets<Thread>::ExposedObject)
111+
CDAC_TYPE_FIELD(Thread, GCHandle, LastThrownObject, cdac_offsets<Thread>::LastThrownObject)
109112
CDAC_TYPE_FIELD(Thread, pointer, LinkNext, cdac_offsets<Thread>::Link)
110113
CDAC_TYPE_END(Thread)
111114

src/coreclr/vm/threads.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4044,7 +4044,10 @@ class Thread
40444044
template<>
40454045
struct cdac_offsets<Thread>
40464046
{
4047+
static constexpr size_t Id = offsetof(Thread, m_ThreadId);
4048+
static constexpr size_t OSId = offsetof(Thread, m_OSThreadId);
40474049
static constexpr size_t ExposedObject = offsetof(Thread, m_ExposedObject);
4050+
static constexpr size_t LastThrownObject = offsetof(Thread, m_LastThrownObjectHandle);
40484051
static constexpr size_t Link = offsetof(Thread, m_Link);
40494052
};
40504053

src/native/managed/cdacreader/src/Contracts/Thread.cs

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ internal record struct ThreadStoreCounts(
1717
int PendingThreadCount,
1818
int DeadThreadCount);
1919

20+
internal record struct ThreadData(
21+
uint Id,
22+
TargetPointer NextThread);
23+
2024
internal interface IThread : IContract
2125
{
2226
static string IContract.Name { get; } = nameof(Thread);
@@ -33,6 +37,7 @@ static IContract IContract.Create(Target target, int version)
3337

3438
public virtual ThreadStoreData GetThreadStoreData() => throw new NotImplementedException();
3539
public virtual ThreadStoreCounts GetThreadCounts() => throw new NotImplementedException();
40+
public virtual ThreadData GetThreadData(TargetPointer thread) => throw new NotImplementedException();
3641
}
3742

3843
internal readonly struct Thread : IThread
@@ -51,8 +56,10 @@ internal Thread_1(Target target, TargetPointer threadStore)
5156
_target = target;
5257
_threadStoreAddr = threadStore;
5358

59+
// Get the offset into Thread of the SLink. We use this to find the actual
60+
// first thread from the linked list node contained by the first thread.
5461
Target.TypeInfo type = _target.GetTypeInfo(DataType.Thread);
55-
_threadLinkOffset = (ulong)type.Fields["LinkNext"].Offset;
62+
_threadLinkOffset = (ulong)type.Fields[nameof(Data.Thread.LinkNext)].Offset;
5663
}
5764

5865
ThreadStoreData IThread.GetThreadStoreData()
@@ -68,7 +75,7 @@ ThreadStoreData IThread.GetThreadStoreData()
6875

6976
return new ThreadStoreData(
7077
threadStore.ThreadCount,
71-
new TargetPointer(threadStore.FirstThreadLink - _threadLinkOffset),
78+
GetThreadFromLink(threadStore.FirstThreadLink),
7279
_target.ReadGlobalPointer(Constants.Globals.FinalizerThread),
7380
_target.ReadGlobalPointer(Constants.Globals.GCThread));
7481
}
@@ -90,4 +97,29 @@ ThreadStoreCounts IThread.GetThreadCounts()
9097
threadStore.PendingCount,
9198
threadStore.DeadCount);
9299
}
100+
101+
ThreadData IThread.GetThreadData(TargetPointer threadPointer)
102+
{
103+
Data.Thread? thread;
104+
if (!_target.ProcessedData.TryGet(threadPointer, out thread))
105+
{
106+
thread = new Data.Thread(_target, threadPointer);
107+
108+
// Still okay if processed data is already registered by someone else.
109+
_ = _target.ProcessedData.TryRegister(threadPointer, thread);
110+
}
111+
112+
return new ThreadData(
113+
thread.Id,
114+
GetThreadFromLink(thread.LinkNext));
115+
}
116+
117+
private TargetPointer GetThreadFromLink(TargetPointer threadLink)
118+
{
119+
if (threadLink == TargetPointer.Null)
120+
return TargetPointer.Null;
121+
122+
// Get the address of the thread containing the link
123+
return new TargetPointer(threadLink - _threadLinkOffset);
124+
}
93125
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace Microsoft.Diagnostics.DataContractReader.Data;
5+
6+
internal sealed class Thread
7+
{
8+
public Thread(Target target, TargetPointer address)
9+
{
10+
Target.TypeInfo type = target.GetTypeInfo(DataType.Thread);
11+
12+
Id = target.Read<uint>(address + (ulong)type.Fields[nameof(Id)].Offset);
13+
LinkNext = target.ReadPointer(address + (ulong)type.Fields[nameof(LinkNext)].Offset);
14+
}
15+
16+
public uint Id { get; init; }
17+
internal TargetPointer LinkNext { get; init; }
18+
}

src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,24 @@ public int GetBreakingChangeVersion()
107107
public unsafe int GetSyncBlockCleanupData(ulong addr, void* data) => HResults.E_NOTIMPL;
108108
public unsafe int GetSyncBlockData(uint number, void* data) => HResults.E_NOTIMPL;
109109
public unsafe int GetThreadAllocData(ulong thread, void* data) => HResults.E_NOTIMPL;
110-
public unsafe int GetThreadData(ulong thread, DacpThreadData* data) => HResults.E_NOTIMPL;
110+
111+
public unsafe int GetThreadData(ulong thread, DacpThreadData* data)
112+
{
113+
try
114+
{
115+
Contracts.IThread contract = _target.Contracts.Thread;
116+
Contracts.ThreadData threadData = contract.GetThreadData(thread);
117+
data->corThreadId = (int)threadData.Id;
118+
data->nextThread = threadData.NextThread;
119+
}
120+
catch (Exception ex)
121+
{
122+
return ex.HResult;
123+
}
124+
125+
// TODO: [cdac] Implement/populate rest of thread data fields
126+
return HResults.E_NOTIMPL;
127+
}
111128
public unsafe int GetThreadFromThinlockID(uint thinLockId, ulong* pThread) => HResults.E_NOTIMPL;
112129
public unsafe int GetThreadLocalModuleData(ulong thread, uint index, void* data) => HResults.E_NOTIMPL;
113130
public unsafe int GetThreadpoolData(void* data) => HResults.E_NOTIMPL;

0 commit comments

Comments
 (0)