/// /// <summary> /// Wait on a set of handles until one of them becomes signaled with a specified time out. /// /// !!! If you change this method, please review WaitHandle.WaitAny() /// and see if the changes need to be propagated there. /// </summary> /// public void InterruptAwareWaitOne() { // Retrieve current thread information Thread currentThread = Thread.CurrentThread; Thread target = null; int unblockedBy; ThreadEntry[] entries = currentThread.GetWaitEntries(1); // Before we attempting to enqueue ourselves into the wait queues make sure // we disable abort currentThread.DelayStop(true); // Perepare for a wait - enqueue ourselves into every wait handle unblockedBy = InterruptAwarePreWaitAnyInternal(currentThread, singleHandle, entries, 1); // If we are in the process of blocking: Block if (UninitWait == unblockedBy) { // Allow thread to be aborted at this point currentThread.DelayStop(false); // Write out log record Monitoring.Log(Monitoring.Provider.Thread, (ushort)ThreadEvent.WaitAny, 0, 0, 0, (uint)currentThread.threadIndex, 0, 0); // Let scheduler know that we are blocking Kernel.TheScheduler.OnThreadBlocked(currentThread, SchedulerTime.MaxValue); // Our thread is about to run so we can disassociate it from wait handles InterruptAwarePostWaitAnyInternal(currentThread, singleHandle, entries, 1); // Thread has the unblocked information unblockedBy = currentThread.UnblockedBy; } // Assert post condition: since there is no timeout, and we are waiting // on a single handle, the unblockedBy must be 0 VTable.Assert(unblockedBy == 0); // Complete wait CompleteWait(currentThread); // When we were signalged delay abort has been set - now we can turn it off // For mutex complete wait will add delay abort. It will remain on until // mutex is released currentThread.DelayStop(false); // Make sure that we pay attention to abort currentThread.ProcessAbortIfRequired(); }
protected override void CompleteWait(Thread ownerThread) { // Assert preconditions VTable.Assert(Thread.CurrentThread == ownerThread); // Update recursion counter this.acquired++; //If this is first time we acquired mutex don't forget to update owner if (this.acquired == 1) { if (this.isKernelObject) { // Kernel thread can't be stop if it owns mutex ownerThread.DelayStop(true); } this.owner = ownerThread; } }
/// /// <summary> /// Constructor ///</summary> /// /// <param name="initiallyOwned">Initial state of a mutex</param> /// <param name="isKernelObject"> /// True if this mutex is created by kernel and therefore used by kernel threads. /// False if this mutex is created by a SIP and therefore used only by the SIP. /// /// A kernel thread is not allowed to be forcibly stopped while owning a mutex, /// whereas SIP threads can be forcibly stopped while owning a mutex. This doesn't /// create problems for SIPs because the only time a SIP thread is forced to stop is /// during process torn down. /// </param> /// /// <remark> We assume that mutex can initially be owned by current thread only </remark> /// public Mutex(bool initiallyOwned, bool isKernelObject) : base(initiallyOwned ? WaitHandle.SignalState.Unsignaled : WaitHandle.SignalState.Signaled, WaitHandle.SignalState.Unsignaled, SpinLock.Types.Mutex) { this.isKernelObject = isKernelObject; if (initiallyOwned) { Thread currentThread = Thread.CurrentThread; this.owner = Thread.CurrentThread; if (this.isKernelObject) { // Kernel thread can't be stop if it owns mutex currentThread.DelayStop(true); } this.acquired = 1; } }
/// /// <summary> /// Wait on a set of handles until one of them becomes signaled with a specified time out. /// </summary> /// /// <param name="waitHandles">Wait handles to wait on </param> /// <param name="waitHandlesCount">A number of wait handles to wait on </param> /// <param name="stop">Time out </param> /// public static int WaitAny( WaitHandle[] waitHandles, int waitHandlesCount, SchedulerTime stop) { // Retrieve current thread information Thread currentThread = Thread.CurrentThread; Thread target = null; int unblockedBy; ThreadEntry[] entries = currentThread.GetWaitEntries( waitHandlesCount); // Before we attempting to enqueue ourselves into the wait queues make sure // we disable abort currentThread.DelayStop(true); // Perepare for a wait - enqueue ourselves into every wait handle unblockedBy = PreWaitAnyInternal(currentThread, waitHandles, entries, waitHandlesCount); // If we are in the process of blocking: Block if (UninitWait == unblockedBy) { // Allow thread to be aborted at this point currentThread.DelayStop(false); // Update thread WaitFor information: Indicate every one that we waiting - // scheduler ones wakes us up is responsible for cleaning up wait information // by using ResetWaitInfo call //currentThread.UpdateWaitInfo (waitHandles, // waitHandlesCount, // entries, // stop); // Write out log record Monitoring.Log(Monitoring.Provider.Thread, (ushort)ThreadEvent.WaitAny, 0, (uint)stop.Ticks, (uint)(stop.Ticks >> 32), (uint)currentThread.threadIndex, 0, 0); // Let scheduler know that we are blocking Kernel.TheScheduler.OnThreadBlocked(currentThread, stop); // Our thread is about to run so we can disassociate it from wait handles PostWaitAnyInternal(currentThread, waitHandles, entries, waitHandlesCount); // Thread has the unblocked information unblockedBy = currentThread.UnblockedBy; } // Assert post condition: unblocked by can't be uninitialized VTable.Assert(unblockedBy != WaitHandle.UninitWait); // If there are wait handles and we were unblocked by not the timeout if (waitHandles != null && unblockedBy >= 0 && unblockedBy < waitHandlesCount) { // Complete wait waitHandles[unblockedBy].CompleteWait(currentThread); // When we were signalged delay abort has been set - now we can turn it off // For mutex complete wait will add delay abort. It will remain on until // mutex is released currentThread.DelayStop(false); } // Make sure that we pay attention to abort currentThread.ProcessAbortIfRequired(); return(unblockedBy); }