Exemplo n.º 1
0
        private DesktopBlockingObject FindMonitor(ulong start, ulong stop)
        {
            ulong obj = 0;

            foreach (ulong ptr in EnumeratePointersInRange(start, stop))
            {
                ulong tmp = 0;
                if (_runtime.ReadPointer(ptr, out tmp))
                {
                    if (_syncblks.TryGetValue(tmp, out tmp))
                    {
                        obj = tmp;
                        break;
                    }
                }
            }

            DesktopBlockingObject result = null;

            if (obj != 0 && _monitors.TryGetValue(obj, out result))
            {
                return(result);
            }

            return(null);
        }
Exemplo n.º 2
0
        private DesktopBlockingObject FindLocks(ulong start, ulong stop, Func <ulong, ClrType, bool> isCorrectType)
        {
            foreach (ulong ptr in EnumeratePointersInRange(start, stop))
            {
                ulong val = 0;
                if (_runtime.ReadPointer(ptr, out val))
                {
                    DesktopBlockingObject result = null;
                    if (_locks.TryGetValue(val, out result) && isCorrectType(val, _heap.GetObjectType(val)))
                    {
                        return(result);
                    }
                }
            }

            return(null);
        }
Exemplo n.º 3
0
        internal DesktopBlockingObject[] InitLockInspection()
        {
            if (_result != null)
            {
                return(_result);
            }

            // First, enumerate all thinlocks on the heap.
            foreach (var seg in _heap.Segments)
            {
                for (ulong obj = seg.FirstObject; obj != 0; obj = seg.NextObject(obj))
                {
                    ClrType type = _heap.GetObjectType(obj);
                    if (IsReaderWriterLock(obj, type))
                    {
                        _locks[obj] = CreateRWLObject(obj, type);
                    }
                    else if (IsReaderWriterSlim(obj, type))
                    {
                        _locks[obj] = CreateRWSObject(obj, type);
                    }

                    // Does this object have a syncblk with monitor associated with it?
                    if (!_heap.GetObjectHeader(obj, out uint header))
                    {
                        continue;
                    }

                    if ((header & (BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX | BIT_SBLK_SPIN_LOCK)) != 0)
                    {
                        continue;
                    }

                    uint threadId = header & SBLK_MASK_LOCK_THREADID;
                    if (threadId == 0)
                    {
                        continue;
                    }

                    ClrThread thread = _runtime.GetThreadFromThinlockID(threadId);
                    if (thread != null)
                    {
                        int recursion = ((int)header & SBLK_MASK_LOCK_RECLEVEL) >> SBLK_RECLEVEL_SHIFT;
                        _monitors[obj] = new DesktopBlockingObject(obj, true, recursion + 1, thread, BlockingReason.Monitor);
                    }
                }
            }

            // Enumerate syncblocks to find locks
            int syncblkCnt = _runtime.GetSyncblkCount();

            for (int i = 0; i < syncblkCnt; ++i)
            {
                ISyncBlkData data = _runtime.GetSyncblkData(i);
                if (data == null || data.Free)
                {
                    continue;
                }

                _syncblks[data.Address] = data.Object;
                _syncblks[data.Object]  = data.Object;
                ClrThread thread = null;
                if (data.MonitorHeld)
                {
                    ulong threadAddr = data.OwningThread;
                    foreach (var clrThread in _runtime.Threads)
                    {
                        if (clrThread.Address == threadAddr)
                        {
                            thread = clrThread;
                            break;
                        }
                    }
                }

                _monitors[data.Object] = new DesktopBlockingObject(data.Object, data.MonitorHeld, (int)data.Recursion, thread, BlockingReason.Monitor);
            }

            SetThreadWaiters();

            int total = _monitors.Count + _locks.Count + _joinLocks.Count + _waitLocks.Count;

            _result = new DesktopBlockingObject[total];

            int j = 0;

            foreach (DesktopBlockingObject blocker in _monitors.Values)
            {
                _result[j++] = blocker;
            }

            foreach (DesktopBlockingObject blocker in _locks.Values)
            {
                _result[j++] = blocker;
            }

            foreach (DesktopBlockingObject blocker in _joinLocks.Values)
            {
                _result[j++] = blocker;
            }

            foreach (DesktopBlockingObject blocker in _waitLocks.Values)
            {
                _result[j++] = blocker;
            }

            Debug.Assert(j == _result.Length);

            // Free up some memory.
            _monitors  = null;
            _locks     = null;
            _joinLocks = null;
            _waitLocks = null;
            _syncblks  = null;

            return(_result);
        }
Exemplo n.º 4
0
        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());
            }
        }