File: Internals\System\Runtime\SignalGate.cs
Web Access
Project: src\src\System.ServiceModel.Primitives\src\System.ServiceModel.Primitives.csproj (System.ServiceModel.Primitives)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
 
using System.Threading;
 
namespace System.Runtime
{
    [Fx.Tag.SynchronizationPrimitive(Fx.Tag.BlocksUsing.NonBlocking)]
    internal class SignalGate
    {
        [Fx.Tag.SynchronizationObject(Blocking = false, Kind = Fx.Tag.SynchronizationKind.InterlockedNoSpin)]
        private int _state;
 
        public SignalGate()
        {
        }
 
        internal bool IsLocked
        {
            get
            {
                return _state == GateState.Locked;
            }
        }
 
        internal bool IsSignalled
        {
            get
            {
                return _state == GateState.Signalled;
            }
        }
 
        // Returns true if this brings the gate to the Signalled state.
        // Transitions - Locked -> SignalPending | Completed before it was unlocked
        //               Unlocked -> Signaled
        public bool Signal()
        {
            int lastState = _state;
            if (lastState == GateState.Locked)
            {
                lastState = Interlocked.CompareExchange(ref _state, GateState.SignalPending, GateState.Locked);
            }
            if (lastState == GateState.Unlocked)
            {
                _state = GateState.Signalled;
                return true;
            }
 
            if (lastState != GateState.Locked)
            {
                ThrowInvalidSignalGateState();
            }
            return false;
        }
 
        // Returns true if this brings the gate to the Signalled state.
        // Transitions - SignalPending -> Signaled | return the AsyncResult since the callback already 
        //                                         | completed and provided the result on its thread
        //               Locked -> Unlocked
        public bool Unlock()
        {
            int lastState = _state;
            if (lastState == GateState.Locked)
            {
                lastState = Interlocked.CompareExchange(ref _state, GateState.Unlocked, GateState.Locked);
            }
            if (lastState == GateState.SignalPending)
            {
                _state = GateState.Signalled;
                return true;
            }
 
            if (lastState != GateState.Locked)
            {
                ThrowInvalidSignalGateState();
            }
            return false;
        }
 
        // This is factored out to allow Signal and Unlock to be inlined.
        private void ThrowInvalidSignalGateState()
        {
            throw Fx.Exception.AsError(new InvalidOperationException(InternalSR.InvalidSemaphoreExit));
        }
 
        private static class GateState
        {
            public const int Locked = 0;
            public const int SignalPending = 1;
            public const int Unlocked = 2;
            public const int Signalled = 3;
        }
    }
    [Fx.Tag.SynchronizationPrimitive(Fx.Tag.BlocksUsing.NonBlocking)]
 
    internal class SignalGate<T> : SignalGate
    {
        private T _result;
 
        public SignalGate()
            : base()
        {
        }
 
        public bool Signal(T result)
        {
            _result = result;
            return Signal();
        }
 
        public bool Unlock(out T result)
        {
            if (Unlock())
            {
                result = _result;
                return true;
            }
 
            result = default(T);
            return false;
        }
    }
}