Skip to content

Instantly share code, notes, and snippets.

@kevingosse
Created October 12, 2021 11:41
Show Gist options
  • Save kevingosse/65b310d285a201a5487c0a32a48130d7 to your computer and use it in GitHub Desktop.
Save kevingosse/65b310d285a201a5487c0a32a48130d7 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Microsoft.Diagnostics.Runtime;
namespace ClrmdAsyncLocal
{
internal class Program
{
static void Main(string[] args)
{
const string path = @"C:\Users\kevin.gosse\Desktop\blog\asynclocal\ClientApp.exe_210916_114422.dmp";
var target = DataTarget.LoadDump(path);
var runtime = target.ClrVersions.First().CreateRuntime();
var heap = runtime.Heap;
var array = heap.GetProxies<AsyncLocal<int>[]>().First();
foreach (var item in array)
{
Console.WriteLine($"Values stored in AsyncLocal {item}:");
foreach (var (threadId, value) in ExtractAsyncLocalValues(heap, (ulong)item))
{
Console.WriteLine($" - {threadId}: {(int)value}");
}
}
Console.ReadLine();
}
private static IEnumerable<(int threadId, dynamic value)> ExtractAsyncLocalValues(ClrHeap heap, ulong address)
{
foreach (var thread in heap.GetProxies<Thread>())
{
int threadId = thread._managedThreadId;
var localValues = thread._executionContext?.m_localValues;
foreach ((dynamic key, dynamic value) pair in ReadAsyncLocalStorage(localValues))
{
if ((ulong)pair.key == address)
{
yield return (threadId, pair.value);
break;
}
}
}
}
private static IEnumerable<(dynamic key, dynamic value)> ReadAsyncLocalStorage(dynamic storage)
{
if (storage == null)
{
return Enumerable.Empty<(dynamic key, dynamic value)>();
}
ClrType type = storage.GetClrType();
return type.Name switch
{
"System.Threading.AsyncLocalValueMap+OneElementAsyncLocalValueMap" => ReadOneElementAsyncLocalValueMap(storage),
"System.Threading.AsyncLocalValueMap+TwoElementAsyncLocalValueMap" => ReadTwoElementAsyncLocalValueMap(storage),
"System.Threading.AsyncLocalValueMap+ThreeElementAsyncLocalValueMap" => ReadThreeElementAsyncLocalValueMap(storage),
"System.Threading.AsyncLocalValueMap+MultiElementAsyncLocalValueMap" => ReadMultiElementAsyncLocalValueMap(storage),
"System.Threading.AsyncLocalValueMap+ManyElementAsyncLocalValueMap" => ReadManyElementAsyncLocalValueMap(storage),
_ => throw new InvalidOperationException($"Unexpected asynclocal storage type: {type.Name}")
};
}
private static IEnumerable<(dynamic key, dynamic value)> ReadOneElementAsyncLocalValueMap(dynamic storage)
{
yield return (storage._key1, storage._value1);
}
private static IEnumerable<(dynamic key, dynamic value)> ReadTwoElementAsyncLocalValueMap(dynamic storage)
{
yield return (storage._key1, storage._value1);
yield return (storage._key2, storage._value2);
}
private static IEnumerable<(dynamic key, dynamic value)> ReadThreeElementAsyncLocalValueMap(dynamic storage)
{
yield return (storage._key1, storage._value1);
yield return (storage._key2, storage._value2);
yield return (storage._key3, storage._value3);
}
private static IEnumerable<(dynamic key, dynamic value)> ReadMultiElementAsyncLocalValueMap(dynamic storage)
{
foreach (var kvp in storage._keyValues)
{
yield return (kvp.key, kvp.value);
}
}
private static IEnumerable<(dynamic key, dynamic value)> ReadManyElementAsyncLocalValueMap(dynamic storage)
{
foreach (var entry in storage._entries)
{
if (entry.key != null)
{
yield return (entry.key, entry.value);
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment