public static SafeWaitHandle?CreateNamedMutex(bool initiallyOwned, string name, out bool createdNew) { // For initially owned, newly created named mutexes, there is a potential race // between adding the mutex to the named object table and initially acquiring it. // To avoid the possibility of another thread retrieving the mutex via its name // before we managed to acquire it, we perform both steps while holding s_lock. LockHolder lockHolder = new LockHolder(s_lock); try { WaitableObject?waitableObject = WaitableObject.CreateNamedMutex_Locked(name, out createdNew); if (waitableObject == null) { return(null); } SafeWaitHandle safeWaitHandle = NewHandle(waitableObject); if (!initiallyOwned || !createdNew) { return(safeWaitHandle); } // Acquire the mutex. A thread's <see cref="ThreadWaitInfo"/> has a reference to all <see cref="Mutex"/>es locked // by the thread. See <see cref="ThreadWaitInfo.LockedMutexesHead"/>. So, acquire the lock only after all // possibilities for exceptions have been exhausted. ThreadWaitInfo waitInfo = Thread.CurrentThread.WaitInfo; int status = waitableObject.Wait_Locked(waitInfo, timeoutMilliseconds: 0, interruptible: false, prioritize: false, ref lockHolder); Debug.Assert(status == 0); return(safeWaitHandle); } finally { lockHolder.Dispose(); } }
public int SignalSemaphore(int count, ref LockHolder lockHolder) { s_lock.VerifyIsLocked(); Debug.Assert(count > 0); if (!IsSemaphore) { lockHolder.Dispose(); WaitHandle.ThrowInvalidHandleException(); } int oldSignalCount = _signalCount; Debug.Assert(oldSignalCount <= _maximumSignalCount); if (count > _maximumSignalCount - oldSignalCount) { lockHolder.Dispose(); throw new SemaphoreFullException(); } if (oldSignalCount != 0) { _signalCount = oldSignalCount + count; return(oldSignalCount); } for (ThreadWaitInfo.WaitedListNode?waiterNode = _waitersHead, nextWaiterNode; waiterNode != null; waiterNode = nextWaiterNode) { // Signaling the waiter will unregister the waiter node, so keep the next node before trying nextWaiterNode = waiterNode.NextThread; if (waiterNode.WaitInfo.TrySignalToSatisfyWait(waiterNode, isAbandonedMutex: false) && --count == 0) { return(oldSignalCount); } } _signalCount = count; return(oldSignalCount); }
public void SignalMutex(ref LockHolder lockHolder) { s_lock.VerifyIsLocked(); if (!IsMutex) { lockHolder.Dispose(); WaitHandle.ThrowInvalidHandleException(); } if (IsSignaled || _ownershipInfo !.Thread != Thread.CurrentThread) { lockHolder.Dispose(); throw new ApplicationException(SR.Arg_SynchronizationLockException); } if (!_ownershipInfo !.TryDecrementReacquireCount()) { SignalMutex(isAbandoned: false); } }
public static int SignalAndWait( WaitableObject waitableObjectToSignal, WaitableObject waitableObjectToWaitOn, int timeoutMilliseconds, bool interruptible = true, bool prioritize = false) { Debug.Assert(waitableObjectToSignal != null); Debug.Assert(waitableObjectToWaitOn != null); Debug.Assert(timeoutMilliseconds >= -1); ThreadWaitInfo waitInfo = Thread.CurrentThread.WaitInfo; LockHolder lockHolder = new LockHolder(s_lock); try { // A pending interrupt does not signal the specified handle if (interruptible && waitInfo.CheckAndResetPendingInterrupt) { lockHolder.Dispose(); throw new ThreadInterruptedException(); } try { waitableObjectToSignal.Signal(1, ref lockHolder); } catch (SemaphoreFullException ex) { s_lock.VerifyIsNotLocked(); throw new InvalidOperationException(SR.Threading_WaitHandleTooManyPosts, ex); } return(waitableObjectToWaitOn.Wait_Locked(waitInfo, timeoutMilliseconds, interruptible, prioritize, ref lockHolder)); } finally { lockHolder.Dispose(); } }
public static void ReleaseMutex(WaitableObject waitableObject) { Debug.Assert(waitableObject != null); LockHolder lockHolder = new LockHolder(s_lock); try { waitableObject.SignalMutex(ref lockHolder); } finally { lockHolder.Dispose(); } }
public static void ResetEvent(WaitableObject waitableObject) { Debug.Assert(waitableObject != null); LockHolder lockHolder = new LockHolder(s_lock); try { waitableObject.UnsignalEvent(ref lockHolder); } finally { lockHolder.Dispose(); } }
public void UnsignalEvent(ref LockHolder lockHolder) { s_lock.VerifyIsLocked(); if (!IsEvent) { lockHolder.Dispose(); WaitHandle.ThrowInvalidHandleException(); } if (IsSignaled) { --_signalCount; } }
public int Wait(ThreadWaitInfo waitInfo, int timeoutMilliseconds, bool interruptible, bool prioritize) { Debug.Assert(waitInfo != null); Debug.Assert(waitInfo.Thread == Thread.CurrentThread); Debug.Assert(timeoutMilliseconds >= -1); var lockHolder = new LockHolder(s_lock); try { if (interruptible && waitInfo.CheckAndResetPendingInterrupt) { lockHolder.Dispose(); throw new ThreadInterruptedException(); } return(Wait_Locked(waitInfo, timeoutMilliseconds, interruptible, prioritize, ref lockHolder)); } finally { lockHolder.Dispose(); } }
public static int ReleaseSemaphore(WaitableObject waitableObject, int count) { Debug.Assert(waitableObject != null); Debug.Assert(count > 0); LockHolder lockHolder = new LockHolder(s_lock); try { return(waitableObject.SignalSemaphore(count, ref lockHolder)); } finally { lockHolder.Dispose(); } }
/// <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 void SignalEvent(ref LockHolder lockHolder) { s_lock.VerifyIsLocked(); switch (_type) { case WaitableObjectType.ManualResetEvent: SignalManualResetEvent(); break; case WaitableObjectType.AutoResetEvent: SignalAutoResetEvent(); break; default: lockHolder.Dispose(); WaitHandle.ThrowInvalidHandleException(); break; } }
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; } } } }
public int Wait(int timeoutMilliseconds, bool interruptible, bool isSleep, ref LockHolder lockHolder) { if (isSleep) { s_lock.VerifyIsNotLocked(); } else { s_lock.VerifyIsLocked(); } Debug.Assert(_thread == Thread.CurrentThread); Debug.Assert(timeoutMilliseconds >= -1); Debug.Assert(timeoutMilliseconds != 0); // caller should have taken care of it _thread.SetWaitSleepJoinState(); // <see cref="_waitMonitor"/> must be acquired before <see cref="s_lock"/> is released, to ensure that there is // no gap during which a waited object may be signaled to satisfy the wait but the thread may not yet be in a // wait state to accept the signal _waitMonitor.Acquire(); if (!isSleep) { lockHolder.Dispose(); } Debug.Assert(_waitedObjectIndexThatSatisfiedWait < 0); Debug.Assert(_waitSignalState == WaitSignalState.NotWaiting); // A signaled state may be set only when the thread is in one of the following states _waitSignalState = interruptible ? WaitSignalState.Waiting_Interruptible : WaitSignalState.Waiting; try { if (isSleep && interruptible && CheckAndResetPendingInterrupt) { throw new ThreadInterruptedException(); } if (timeoutMilliseconds < 0) { do { _waitMonitor.Wait(); } while (IsWaiting); int waitResult = ProcessSignaledWaitState(); Debug.Assert(waitResult != WaitHandle.WaitTimeout); return(waitResult); } int elapsedMilliseconds = 0; int startTimeMilliseconds = Environment.TickCount; while (true) { bool monitorWaitResult = _waitMonitor.Wait(timeoutMilliseconds - elapsedMilliseconds); // It's possible for the wait to have timed out, but before the monitor could reacquire the lock, a // signaler could have acquired it and signaled to satisfy the wait or interrupt the thread. Accept the // signal and ignore the wait timeout. int waitResult = ProcessSignaledWaitState(); if (waitResult != WaitHandle.WaitTimeout) { return(waitResult); } if (monitorWaitResult) { elapsedMilliseconds = Environment.TickCount - startTimeMilliseconds; if (elapsedMilliseconds < timeoutMilliseconds) { continue; } } // Timeout Debug.Assert(_waitedObjectIndexThatSatisfiedWait < 0); break; } } finally { _waitSignalState = WaitSignalState.NotWaiting; _waitMonitor.Release(); _thread.ClearWaitSleepJoinState(); } // Timeout. It's ok to read <see cref="_waitedCount"/> without acquiring <see cref="s_lock"/> here, because it // is initially set by this thread, and another thread cannot unregister this thread's wait without first // signaling this thread, in which case this thread wouldn't be timing out. Debug.Assert(isSleep == (_waitedCount == 0)); if (!isSleep) { s_lock.Acquire(); UnregisterWait(); s_lock.Release(); } return(WaitHandle.WaitTimeout); }