Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/design/datacontracts/Thread.md
Original file line number Diff line number Diff line change
Expand Up @@ -284,9 +284,9 @@ TargetPointer IThread.IdToThread(uint id)
{
TargetPointer idDispenserPointer = target.ReadGlobalPointer(Constants.Globals.ThinlockThreadIdDispenser);
TargetPointer idDispenser = target.ReadPointer(idDispenserPointer);
uint HighestId = target.ReadPointer(idDispenser + /* IdDispenser::HighestId offset */);
uint HighestId = target.Read<uint>(idDispenser + /* IdDispenser::HighestId offset */);
TargetPointer threadPtr = TargetPointer.Null;
if (id < HighestId)
if (id <= HighestId)
threadPtr = target.ReadPointer(idDispenser + /* IdDispenser::IdToThread offset + (index into IdToThread array * size of array elements (== size of target pointer)) */);
Comment thread
max-charlamb marked this conversation as resolved.
return threadPtr;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ TargetPointer IThread.IdToThread(uint id)
TargetPointer idDispenser = _target.ReadPointer(idDispenserPtr);
Data.IdDispenser idDispenserObj = _target.ProcessedData.GetOrAdd<Data.IdDispenser>(idDispenser);
TargetPointer threadPtr = TargetPointer.Null;
if (id < idDispenserObj.HighestId)
if (id <= idDispenserObj.HighestId)
threadPtr = _target.ReadPointer(idDispenserObj.IdToThread + (ulong)(id * _target.PointerSize));
return threadPtr;
}
Expand Down
51 changes: 51 additions & 0 deletions src/native/managed/cdac/tests/UnitTests/ThreadTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,57 @@ private static TestPlaceholderTarget CreateTarget(
[DataType.RuntimeThreadLocals] = TargetTestHelpers.CreateTypeInfo(threadBuilder.RuntimeThreadLocalsLayout),
};

[Theory]
[ClassData(typeof(MockTarget.StdArch))]
public void IdToThread_IncludesHighestId(MockTarget.Architecture arch)
{
const uint HighestId = 3;
const ulong ExpectedThread = 0x7000;
TargetTestHelpers helpers = new(arch);
var builder = new TestPlaceholderTarget.Builder(arch);
MockMemorySpace.BumpAllocator allocator = builder.MemoryBuilder.CreateAllocator(0x1000, 0x9000);
TargetTestHelpers.LayoutResult layout = helpers.LayoutFields(
[
new(nameof(Data.IdDispenser.IdToThread), DataType.pointer),
new(nameof(Data.IdDispenser.HighestId), DataType.uint32),
]);

MockMemorySpace.HeapFragment idToThread = allocator.Allocate(
(ulong)((HighestId + 1) * helpers.PointerSize),
"IdToThread");
helpers.WritePointer(
idToThread.Data.AsSpan((int)HighestId * helpers.PointerSize, helpers.PointerSize),
ExpectedThread);

MockMemorySpace.HeapFragment dispenser = allocator.Allocate(layout.Stride, "IdDispenser");
helpers.WritePointer(
dispenser.Data.AsSpan(layout.Fields[nameof(Data.IdDispenser.IdToThread)].Offset, helpers.PointerSize),
idToThread.Address);
helpers.Write(
dispenser.Data.AsSpan(layout.Fields[nameof(Data.IdDispenser.HighestId)].Offset, sizeof(uint)),
HighestId);

MockMemorySpace.HeapFragment global = allocator.Allocate((ulong)helpers.PointerSize, "ThinlockThreadIdDispenser");
helpers.WritePointer(global.Data, dispenser.Address);
MockMemorySpace.HeapFragment threadStoreGlobal = allocator.Allocate((ulong)helpers.PointerSize, "ThreadStore");
helpers.WritePointer(threadStoreGlobal.Data, 0);

Target target = builder
.AddTypes(new Dictionary<DataType, Target.TypeInfo>
{
[DataType.IdDispenser] = new Target.TypeInfo { Fields = layout.Fields, Size = layout.Stride },
[DataType.Thread] = new Target.TypeInfo { Fields = new Dictionary<string, Target.FieldInfo>(), Size = 0 },
})
.AddGlobals(
(Constants.Globals.ThinlockThreadIdDispenser, global.Address),
(Constants.Globals.ThreadStore, threadStoreGlobal.Address))
.AddContract<IThread>("c1")
.Build();

Assert.Equal(new TargetPointer(ExpectedThread), target.Contracts.Thread.IdToThread(HighestId));
Assert.Equal(TargetPointer.Null, target.Contracts.Thread.IdToThread(HighestId + 1));
}

[Theory]
[ClassData(typeof(MockTarget.StdArch))]
public void GetThreadStoreData(MockTarget.Architecture arch)
Expand Down
Loading