Example #1
0
            public static void SatisfyWaitForAll(
                ThreadWaitInfo waitInfo,
                WaitableObject[] waitedObjects,
                int waitedCount,
                int signaledWaitedObjectIndex)
            {
                Debug.Assert(waitInfo != null);
                Debug.Assert(waitInfo.Thread != RuntimeThread.CurrentThread);
                Debug.Assert(waitedObjects != null);
                Debug.Assert(waitedObjects.Length >= waitedCount);
                Debug.Assert(waitedCount > 1);
                Debug.Assert(signaledWaitedObjectIndex >= 0);
                Debug.Assert(signaledWaitedObjectIndex <= WaitHandle.MaxWaitHandles);

                for (int i = 0; i < waitedCount; ++i)
                {
                    Debug.Assert(waitedObjects[i] != null);
                    if (i == signaledWaitedObjectIndex)
                    {
                        continue;
                    }

                    WaitableObject waitedObject = waitedObjects[i];
                    if (waitedObject.IsSignaled)
                    {
                        waitedObject.AcceptSignal(waitInfo);
                        continue;
                    }

                    Debug.Assert(waitedObject.IsMutex);
                    OwnershipInfo ownershipInfo = waitedObject._ownershipInfo;
                    Debug.Assert(ownershipInfo.Thread == waitInfo.Thread);
                    ownershipInfo.IncrementReacquireCount();
                }
            }
            public static int Wait(
                WaitableObject[] waitableObjects,
                int count,
                bool waitForAll,
                ThreadWaitInfo waitInfo,
                int timeoutMilliseconds,
                bool interruptible,
                bool prioritize,
                WaitHandle[] waitHandlesForAbandon)
            {
                s_lock.VerifyIsNotLocked();
                Debug.Assert(waitInfo != null);
                Debug.Assert(waitInfo.Thread == RuntimeThread.CurrentThread);

                Debug.Assert(waitableObjects != null);
                Debug.Assert(waitableObjects.Length >= count);
                Debug.Assert(count > 1);
                Debug.Assert(timeoutMilliseconds >= -1);

                bool needToWait = false;

                s_lock.Acquire();
                try
                {
                    if (interruptible && waitInfo.CheckAndResetPendingInterrupt)
                    {
                        throw new ThreadInterruptedException();
                    }

                    if (!waitForAll)
                    {
                        // Check if any is already signaled
                        for (int i = 0; i < count; ++i)
                        {
                            WaitableObject waitableObject = waitableObjects[i];
                            Debug.Assert(waitableObject != null);

                            if (waitableObject.IsSignaled)
                            {
                                bool isAbandoned = waitableObject.IsAbandonedMutex;
                                waitableObject.AcceptSignal(waitInfo);
                                if (isAbandoned)
                                {
                                    if (waitHandlesForAbandon == null)
                                    {
                                        throw new AbandonedMutexException();
                                    }
                                    else
                                    {
                                        throw new AbandonedMutexException(i, waitHandlesForAbandon[i]);
                                    }
                                }
                                return(i);
                            }

                            if (waitableObject.IsMutex)
                            {
                                OwnershipInfo ownershipInfo = waitableObject._ownershipInfo;
                                if (ownershipInfo.Thread == waitInfo.Thread)
                                {
                                    if (!ownershipInfo.CanIncrementReacquireCount)
                                    {
                                        throw new OverflowException(SR.Overflow_MutexReacquireCount);
                                    }
                                    ownershipInfo.IncrementReacquireCount();
                                    return(i);
                                }
                            }
                        }
                    }
                    else
                    {
                        // Check if all are already signaled
                        bool areAllSignaled      = true;
                        bool isAnyAbandonedMutex = false;
                        for (int i = 0; i < count; ++i)
                        {
                            WaitableObject waitableObject = waitableObjects[i];
                            Debug.Assert(waitableObject != null);

                            if (waitableObject.IsSignaled)
                            {
                                if (!isAnyAbandonedMutex && waitableObject.IsAbandonedMutex)
                                {
                                    isAnyAbandonedMutex = true;
                                }
                                continue;
                            }

                            if (waitableObject.IsMutex)
                            {
                                OwnershipInfo ownershipInfo = waitableObject._ownershipInfo;
                                if (ownershipInfo.Thread == waitInfo.Thread)
                                {
                                    if (!ownershipInfo.CanIncrementReacquireCount)
                                    {
                                        throw new OverflowException(SR.Overflow_MutexReacquireCount);
                                    }
                                    continue;
                                }
                            }

                            areAllSignaled = false;
                            break;
                        }

                        if (areAllSignaled)
                        {
                            for (int i = 0; i < count; ++i)
                            {
                                WaitableObject waitableObject = waitableObjects[i];
                                if (waitableObject.IsSignaled)
                                {
                                    waitableObject.AcceptSignal(waitInfo);
                                    continue;
                                }

                                Debug.Assert(waitableObject.IsMutex);
                                OwnershipInfo ownershipInfo = waitableObject._ownershipInfo;
                                Debug.Assert(ownershipInfo.Thread == waitInfo.Thread);
                                ownershipInfo.IncrementReacquireCount();
                            }

                            if (isAnyAbandonedMutex)
                            {
                                throw new AbandonedMutexException();
                            }
                            return(0);
                        }
                    }

                    if (timeoutMilliseconds == 0)
                    {
                        return(WaitHandle.WaitTimeout);
                    }

                    waitableObjects = null; // no need to clear this anymore, RegisterWait / Wait will take over from here
                    waitInfo.RegisterWait(count, prioritize, waitForAll);
                    needToWait = true;
                }
                finally
                {
                    if (waitableObjects != null)
                    {
                        for (int i = 0; i < count; ++i)
                        {
                            waitableObjects[i] = null;
                        }
                    }

                    // Once the wait function is called, it will release the lock
                    if (!needToWait)
                    {
                        s_lock.Release();
                    }
                }

                return(waitInfo.Wait(timeoutMilliseconds, interruptible, waitHandlesForAbandon, isSleep: false));
            }
            public static int Wait(
                WaitableObject?[]?waitableObjects,
                int count,
                bool waitForAll,
                ThreadWaitInfo waitInfo,
                int timeoutMilliseconds,
                bool interruptible,
                bool prioritize)
            {
                s_lock.VerifyIsNotLocked();
                Debug.Assert(waitInfo != null);
                Debug.Assert(waitInfo.Thread == Thread.CurrentThread);

                Debug.Assert(waitableObjects != null);
                Debug.Assert(waitableObjects.Length >= count);
                Debug.Assert(count > 1);
                Debug.Assert(timeoutMilliseconds >= -1);

                var lockHolder = new LockHolder(s_lock);

                try
                {
                    if (interruptible && waitInfo.CheckAndResetPendingInterrupt)
                    {
                        lockHolder.Dispose();
                        throw new ThreadInterruptedException();
                    }

                    if (!waitForAll)
                    {
                        // Check if any is already signaled
                        for (int i = 0; i < count; ++i)
                        {
                            WaitableObject waitableObject = waitableObjects[i] !;
                            Debug.Assert(waitableObject != null);

                            if (waitableObject.IsSignaled)
                            {
                                bool isAbandoned = waitableObject.IsAbandonedMutex;
                                waitableObject.AcceptSignal(waitInfo);
                                if (isAbandoned)
                                {
                                    return(WaitHandle.WaitAbandoned + i);
                                }
                                return(WaitHandle.WaitSuccess + i);
                            }

                            if (waitableObject.IsMutex)
                            {
                                OwnershipInfo ownershipInfo = waitableObject._ownershipInfo !;
                                if (ownershipInfo.Thread == waitInfo.Thread)
                                {
                                    if (!ownershipInfo.CanIncrementReacquireCount)
                                    {
                                        lockHolder.Dispose();
                                        throw new OverflowException(SR.Overflow_MutexReacquireCount);
                                    }
                                    ownershipInfo.IncrementReacquireCount();
                                    return(WaitHandle.WaitSuccess + i);
                                }
                            }
                        }
                    }
                    else
                    {
                        // Check if all are already signaled
                        bool areAllSignaled      = true;
                        bool isAnyAbandonedMutex = false;
                        for (int i = 0; i < count; ++i)
                        {
                            WaitableObject waitableObject = waitableObjects[i] !;
                            Debug.Assert(waitableObject != null);

                            if (waitableObject.IsSignaled)
                            {
                                if (!isAnyAbandonedMutex && waitableObject.IsAbandonedMutex)
                                {
                                    isAnyAbandonedMutex = true;
                                }
                                continue;
                            }

                            if (waitableObject.IsMutex)
                            {
                                OwnershipInfo ownershipInfo = waitableObject._ownershipInfo !;
                                if (ownershipInfo.Thread == waitInfo.Thread)
                                {
                                    if (!ownershipInfo.CanIncrementReacquireCount)
                                    {
                                        lockHolder.Dispose();
                                        throw new OverflowException(SR.Overflow_MutexReacquireCount);
                                    }
                                    continue;
                                }
                            }

                            areAllSignaled = false;
                            break;
                        }

                        if (areAllSignaled)
                        {
                            for (int i = 0; i < count; ++i)
                            {
                                WaitableObject waitableObject = waitableObjects[i] !;
                                if (waitableObject.IsSignaled)
                                {
                                    waitableObject.AcceptSignal(waitInfo);
                                    continue;
                                }

                                Debug.Assert(waitableObject.IsMutex);
                                OwnershipInfo ownershipInfo = waitableObject._ownershipInfo !;
                                Debug.Assert(ownershipInfo.Thread == waitInfo.Thread);
                                ownershipInfo.IncrementReacquireCount();
                            }

                            if (isAnyAbandonedMutex)
                            {
                                lockHolder.Dispose();
                                throw new AbandonedMutexException();
                            }
                            return(WaitHandle.WaitSuccess);
                        }
                    }

                    if (timeoutMilliseconds == 0)
                    {
                        return(WaitHandle.WaitTimeout);
                    }

                    waitableObjects = null; // no need to clear this anymore, RegisterWait / Wait will take over from here

                    waitInfo.RegisterWait(count, prioritize, waitForAll);
                    return(waitInfo.Wait(timeoutMilliseconds, interruptible, isSleep: false, ref lockHolder));
                }
                finally
                {
                    lockHolder.Dispose();

                    if (waitableObjects != null)
                    {
                        for (int i = 0; i < count; ++i)
                        {
                            waitableObjects[i] = null;
                        }
                    }
                }
            }