public ThreadWaitInfo(RuntimeThread thread) { Debug.Assert(thread != null); _thread = thread; _waitMonitor = new LowLevelMonitor(); _waitSignalState = WaitSignalState.NotWaiting; _waitedObjectIndexThatSatisfiedWait = -1; _waitedObjects = new WaitHandleArray <WaitableObject>(elementInitializer: null); _waitedListNodes = new WaitHandleArray <WaitedListNode>(i => new WaitedListNode(this, i)); }
public ThreadWaitInfo(Thread thread) { Debug.Assert(thread != null); _thread = thread; _waitMonitor = new LowLevelMonitor(); _waitSignalState = WaitSignalState.NotWaiting; _waitedObjectIndexThatSatisfiedWait = -1; // Preallocate to make waiting for single handle fault-free _waitedObjects = new WaitableObject[1]; _waitedListNodes = new WaitedListNode[1] { new WaitedListNode(this, 0) }; }
public void TrySignalToInterruptWaitOrRecordPendingInterrupt() { s_lock.VerifyIsLocked(); _waitMonitor.Acquire(); if (_waitSignalState != WaitSignalState.Waiting_Interruptible) { RecordPendingInterrupt(); _waitMonitor.Release(); return; } if (_waitedCount != 0) { UnregisterWait(); } Debug.Assert(_waitedObjectIndexThatSatisfiedWait < 0); _waitSignalState = WaitSignalState.NotWaiting_SignaledToInterruptWait; _waitMonitor.Signal_Release(); }
public bool TrySignalToSatisfyWait(WaitedListNode registeredListNode, bool isAbandonedMutex) { s_lock.VerifyIsLocked(); Debug.Assert(_thread != Thread.CurrentThread); Debug.Assert(registeredListNode != null); Debug.Assert(registeredListNode.WaitInfo == this); Debug.Assert(registeredListNode.WaitedObjectIndex >= 0); Debug.Assert(registeredListNode.WaitedObjectIndex < _waitedCount); Debug.Assert(_waitedCount > (_isWaitForAll ? 1 : 0)); int signaledWaitedObjectIndex = registeredListNode.WaitedObjectIndex; bool isWaitForAll = _isWaitForAll; bool wouldAnyMutexReacquireCountOverflow = false; if (isWaitForAll) { // Determine if all waits would be satisfied if (!WaitableObject.WouldWaitForAllBeSatisfiedOrAborted( _thread, _waitedObjects, _waitedCount, signaledWaitedObjectIndex, ref wouldAnyMutexReacquireCountOverflow, ref isAbandonedMutex)) { return(false); } } // The wait would be satisfied. Before making changes to satisfy the wait, acquire the monitor and verify that // the thread can accept a signal. _waitMonitor.Acquire(); if (!IsWaiting) { _waitMonitor.Release(); return(false); } if (isWaitForAll && !wouldAnyMutexReacquireCountOverflow) { // All waits would be satisfied, accept the signals WaitableObject.SatisfyWaitForAll(this, _waitedObjects, _waitedCount, signaledWaitedObjectIndex); } UnregisterWait(); Debug.Assert(_waitedObjectIndexThatSatisfiedWait < 0); if (wouldAnyMutexReacquireCountOverflow) { _waitSignalState = WaitSignalState.NotWaiting_SignaledToAbortWaitDueToMaximumMutexReacquireCount; } else { _waitedObjectIndexThatSatisfiedWait = signaledWaitedObjectIndex; _waitSignalState = isAbandonedMutex ? WaitSignalState.NotWaiting_SignaledToSatisfyWaitWithAbandonedMutex : WaitSignalState.NotWaiting_SignaledToSatisfyWait; } _waitMonitor.Signal_Release(); return(!wouldAnyMutexReacquireCountOverflow); }
public int Wait(int timeoutMilliseconds, bool interruptible, bool isSleep) { 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) { s_lock.Release(); } 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); }