Example #1
0
        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);
                }
            }
Example #4
0
        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();
            }
        }
Example #5
0
        public static void ReleaseMutex(WaitableObject waitableObject)
        {
            Debug.Assert(waitableObject != null);

            LockHolder lockHolder = new LockHolder(s_lock);

            try
            {
                waitableObject.SignalMutex(ref lockHolder);
            }
            finally
            {
                lockHolder.Dispose();
            }
        }
Example #6
0
        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();
                }
            }
Example #9
0
        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);
            }