/// <summary> /// This function does not check for a pending thread interrupt. Callers are expected to do that soon after /// acquiring <see cref="s_lock"/>. /// </summary> public bool Wait_Locked(ThreadWaitInfo waitInfo, int timeoutMilliseconds, bool interruptible, bool prioritize) { s_lock.VerifyIsLocked(); Debug.Assert(waitInfo != null); Debug.Assert(waitInfo.Thread == RuntimeThread.CurrentThread); Debug.Assert(timeoutMilliseconds >= -1); Debug.Assert(!interruptible || !waitInfo.CheckAndResetPendingInterrupt); bool needToWait = false; try { if (IsSignaled) { bool isAbandoned = IsAbandonedMutex; AcceptSignal(waitInfo); if (isAbandoned) { throw new AbandonedMutexException(); } return(true); } if (IsMutex && _ownershipInfo.Thread == waitInfo.Thread) { if (!_ownershipInfo.CanIncrementReacquireCount) { throw new OverflowException(SR.Overflow_MutexReacquireCount); } _ownershipInfo.IncrementReacquireCount(); return(true); } if (timeoutMilliseconds == 0) { return(false); } WaitableObject[] waitableObjects = waitInfo.GetWaitedObjectArray(1); waitableObjects[0] = this; waitInfo.RegisterWait(1, prioritize, isWaitForAll: false); needToWait = true; } finally { // Once the wait function is called, it will release the lock if (!needToWait) { s_lock.Release(); } } return (waitInfo.Wait( timeoutMilliseconds, interruptible, waitHandlesForAbandon: null, isSleep: false) != WaitHandle.WaitTimeout); }
/// <summary> /// This function does not check for a pending thread interrupt. Callers are expected to do that soon after /// acquiring <see cref="s_lock"/>. /// </summary> public int Wait_Locked(ThreadWaitInfo waitInfo, int timeoutMilliseconds, bool interruptible, bool prioritize, ref LockHolder lockHolder) { s_lock.VerifyIsLocked(); Debug.Assert(waitInfo != null); Debug.Assert(waitInfo.Thread == Thread.CurrentThread); Debug.Assert(timeoutMilliseconds >= -1); Debug.Assert(!interruptible || !waitInfo.CheckAndResetPendingInterrupt); if (IsSignaled) { bool isAbandoned = IsAbandonedMutex; AcceptSignal(waitInfo); return(isAbandoned ? WaitHandle.WaitAbandoned : WaitHandle.WaitSuccess); } if (IsMutex && _ownershipInfo != null && _ownershipInfo.Thread == waitInfo.Thread) { if (!_ownershipInfo.CanIncrementReacquireCount) { lockHolder.Dispose(); throw new OverflowException(SR.Overflow_MutexReacquireCount); } _ownershipInfo.IncrementReacquireCount(); return(WaitHandle.WaitSuccess); } if (timeoutMilliseconds == 0) { return(WaitHandle.WaitTimeout); } WaitableObject?[] waitableObjects = waitInfo.GetWaitedObjectArray(1); waitableObjects[0] = this; waitInfo.RegisterWait(1, prioritize, isWaitForAll: false); return (waitInfo.Wait( timeoutMilliseconds, interruptible, isSleep: false, ref lockHolder)); }
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; } } } }