private static string KindString(this BlockingReason kind) { switch (kind) { case BlockingReason.None: return "None"; case BlockingReason.Unknown: return "Unknown"; case BlockingReason.Monitor: return "Monitor"; case BlockingReason.MonitorWait: return "MonitorWait"; case BlockingReason.WaitOne: return "WaitOne"; case BlockingReason.WaitAll: return "WaitAll"; case BlockingReason.WaitAny: return "WaitAny"; case BlockingReason.ThreadJoin: return "ThreadJoin"; case BlockingReason.ReaderAcquired: return "ReaderAcquired"; case BlockingReason.WriterAcquired: return "WriterAcquired"; default: return "Unknown"; } }
public DesktopBlockingObject(ulong obj, bool locked, int recursion, BlockingReason reason) { Object = obj; _locked = locked; RecursionCount = recursion; _reason = reason; }
public DesktopBlockingObject(ulong obj, bool locked, int recursion, BlockingReason reason, ClrThread[] owners) { Object = obj; _locked = locked; RecursionCount = recursion; _reason = reason; _owners = owners; }
public DesktopBlockingObject(ulong obj, bool locked, int recursion, ClrThread owner, BlockingReason reason) { Object = obj; _locked = locked; RecursionCount = recursion; _reason = reason; _owners = new ClrThread[1]; _owners[0] = owner; }
private ClrtBlkObject(ulong address, bool taken, BlockingReason blkReason, int recursionCnt, int typeId, int blockInfoNdx) { _address = address; _recursionCnt = recursionCnt; _blkReason = blkReason; _taken = taken; _index = blockInfoNdx; _typeId = typeId; }
/// <summary> /// Create instance of our version BlockingObject. /// </summary> /// <param name="bo">Instance of BlockingObject from ClrHeap.</param> /// <param name="blockInfoNdx">Index of the owners,waiters information.</param> /// <param name="typeId">Type of this object.</param> public ClrtBlkObject(BlockingObject bo, int blockInfoNdx, int typeId) { _address = bo.Object; _recursionCnt = bo.RecursionCount; _blkReason = bo.Reason; _taken = bo.Taken; _index = blockInfoNdx; _typeId = typeId; }
public static ClrtBlkObject Load(BinaryReader bw) { ulong addr = bw.ReadUInt64(); int recursionCnt = bw.ReadInt32(); BlockingReason blkReason = (BlockingReason)bw.ReadInt32(); int blockInfoNdx = bw.ReadInt32(); int typeId = bw.ReadInt32(); bool taken = bw.ReadBoolean(); return(new ClrtBlkObject(addr, taken, blkReason, recursionCnt, typeId, blockInfoNdx)); }
private void SetThreadWaiters() { HashSet <string> eventTypes = null; List <BlockingObject> blobjs = new List <BlockingObject>(); foreach (DesktopThread thread in _runtime.Threads) { int max = thread.StackTrace.Count; if (max > 10) { max = 10; } blobjs.Clear(); for (int i = 0; i < max; ++i) { DesktopBlockingObject blockingObj = null; ClrMethod method = thread.StackTrace[i].Method; if (method == null) { continue; } ClrType type = method.Type; if (type == null) { continue; } switch (method.Name) { case "AcquireWriterLockInternal": case "FCallUpgradeToWriterLock": case "UpgradeToWriterLock": case "AcquireReaderLockInternal": case "AcquireReaderLock": if (type.Name == "System.Threading.ReaderWriterLock") { blockingObj = FindLocks(thread.StackLimit, thread.StackTrace[i].StackPointer, IsReaderWriterLock); if (blockingObj == null) { blockingObj = FindLocks(thread.StackTrace[i].StackPointer, thread.StackBase, IsReaderWriterLock); } if (blockingObj != null && (blockingObj.Reason == BlockingReason.Unknown || blockingObj.Reason == BlockingReason.None)) { // This should have already been set correctly when the BlockingObject was created. This is just a best-guess. if (method.Name == "AcquireReaderLockInternal" || method.Name == "AcquireReaderLock") { blockingObj.Reason = BlockingReason.WriterAcquired; } else { blockingObj.Reason = BlockingReason.ReaderAcquired; } } } break; case "TryEnterReadLockCore": case "TryEnterReadLock": case "TryEnterUpgradeableReadLock": case "TryEnterUpgradeableReadLockCore": case "TryEnterWriteLock": case "TryEnterWriteLockCore": if (type.Name == "System.Threading.ReaderWriterLockSlim") { blockingObj = FindLocks(thread.StackLimit, thread.StackTrace[i].StackPointer, IsReaderWriterSlim); if (blockingObj == null) { blockingObj = FindLocks(thread.StackTrace[i].StackPointer, thread.StackBase, IsReaderWriterSlim); } if (blockingObj != null && (blockingObj.Reason == BlockingReason.Unknown || blockingObj.Reason == BlockingReason.None)) { // This should have already been set correctly when the BlockingObject was created. This is just a best-guess. if (method.Name == "TryEnterWriteLock" || method.Name == "TryEnterWriteLockCore") { blockingObj.Reason = BlockingReason.ReaderAcquired; } else { blockingObj.Reason = BlockingReason.WriterAcquired; } } } break; case "JoinInternal": case "Join": if (type.Name == "System.Threading.Thread") { if (FindThread(thread.StackLimit, thread.StackTrace[i].StackPointer, out ulong threadAddr, out ClrThread target) || FindThread(thread.StackTrace[i].StackPointer, thread.StackBase, out threadAddr, out target)) { if (!_joinLocks.TryGetValue(target, out blockingObj)) { _joinLocks[target] = blockingObj = new DesktopBlockingObject(threadAddr, true, 0, target, BlockingReason.ThreadJoin); } } } break; case "Wait": case "ObjWait": if (type.Name == "System.Threading.Monitor") { blockingObj = FindMonitor(thread.StackLimit, thread.StackTrace[i].StackPointer); if (blockingObj == null) { blockingObj = FindMonitor(thread.StackTrace[i].StackPointer, thread.StackBase); } blockingObj.Reason = BlockingReason.MonitorWait; } break; case "WaitAny": case "WaitAll": if (type.Name == "System.Threading.WaitHandle") { ulong obj = FindWaitObjects(thread.StackLimit, thread.StackTrace[i].StackPointer, "System.Threading.WaitHandle[]"); if (obj == 0) { obj = FindWaitObjects(thread.StackTrace[i].StackPointer, thread.StackBase, "System.Threading.WaitHandle[]"); } if (obj != 0) { BlockingReason reason = method.Name == "WaitAny" ? BlockingReason.WaitAny : BlockingReason.WaitAll; if (!_waitLocks.TryGetValue(obj, out blockingObj)) { _waitLocks[obj] = blockingObj = new DesktopBlockingObject(obj, true, 0, null, reason); } } } break; case "WaitOne": case "InternalWaitOne": case "WaitOneNative": if (type.Name == "System.Threading.WaitHandle") { if (eventTypes == null) { eventTypes = new HashSet <string> { "System.Threading.Mutex", "System.Threading.Semaphore", "System.Threading.ManualResetEvent", "System.Threading.AutoResetEvent", "System.Threading.WaitHandle", "Microsoft.Win32.SafeHandles.SafeWaitHandle" }; } ulong obj = FindWaitHandle(thread.StackLimit, thread.StackTrace[i].StackPointer, eventTypes); if (obj == 0) { obj = FindWaitHandle(thread.StackTrace[i].StackPointer, thread.StackBase, eventTypes); } if (obj != 0) { if (_waitLocks == null) { _waitLocks = new Dictionary <ulong, DesktopBlockingObject>(); } if (!_waitLocks.TryGetValue(obj, out blockingObj)) { _waitLocks[obj] = blockingObj = new DesktopBlockingObject(obj, true, 0, null, BlockingReason.WaitOne); } } } break; case "TryEnter": case "ReliableEnterTimeout": case "TryEnterTimeout": case "ReliableEnter": case "Enter": if (type.Name == "System.Threading.Monitor") { blockingObj = FindMonitor(thread.StackLimit, thread.StackTrace[i].StackPointer); if (blockingObj != null) { blockingObj.Reason = BlockingReason.Monitor; } } break; } if (blockingObj != null) { bool alreadyEncountered = false; foreach (var blobj in blobjs) { if (blobj.Object == blockingObj.Object) { alreadyEncountered = true; break; } } if (!alreadyEncountered) { blobjs.Add(blockingObj); } } } foreach (DesktopBlockingObject blobj in blobjs) { blobj.AddWaiter(thread); } thread.SetBlockingObjects(blobjs.ToArray()); } }