Created
October 12, 2021 11:41
-
-
Save kevingosse/65b310d285a201a5487c0a32a48130d7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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