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));
            }
Ejemplo n.º 2
0
            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)
                };
            }
Ejemplo n.º 3
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();
            }
Ejemplo n.º 4
0
            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);
            }
Ejemplo n.º 5
0
            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);
            }