private void SetThreadWaiters()

in ClrMemDiag/Desktop/lockinspection.cs [157:341]


        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")
                            {
                                ulong threadAddr;
                                ClrThread target;

                                if (FindThread(thread.StackLimit, thread.StackTrace[i].StackPointer, out threadAddr, out 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>();
                                    eventTypes.Add("System.Threading.Mutex");
                                    eventTypes.Add("System.Threading.Semaphore");
                                    eventTypes.Add("System.Threading.ManualResetEvent");
                                    eventTypes.Add("System.Threading.AutoResetEvent");
                                    eventTypes.Add("System.Threading.WaitHandle");
                                    eventTypes.Add("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 "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());
            }
        }