e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
127 lines
3.5 KiB
C#
127 lines
3.5 KiB
C#
//-----------------------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
namespace System.Runtime
|
|
{
|
|
using System;
|
|
using System.Threading;
|
|
|
|
[Fx.Tag.SynchronizationPrimitive(Fx.Tag.BlocksUsing.NonBlocking)]
|
|
class SignalGate
|
|
{
|
|
[Fx.Tag.SynchronizationObject(Blocking = false, Kind = Fx.Tag.SynchronizationKind.InterlockedNoSpin)]
|
|
int state;
|
|
|
|
public SignalGate()
|
|
{
|
|
}
|
|
|
|
internal bool IsLocked
|
|
{
|
|
get
|
|
{
|
|
return this.state == GateState.Locked;
|
|
}
|
|
}
|
|
|
|
internal bool IsSignalled
|
|
{
|
|
get
|
|
{
|
|
return this.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 = this.state;
|
|
if (lastState == GateState.Locked)
|
|
{
|
|
lastState = Interlocked.CompareExchange(ref this.state, GateState.SignalPending, GateState.Locked);
|
|
}
|
|
if (lastState == GateState.Unlocked)
|
|
{
|
|
this.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 = this.state;
|
|
if (lastState == GateState.Locked)
|
|
{
|
|
lastState = Interlocked.CompareExchange(ref this.state, GateState.Unlocked, GateState.Locked);
|
|
}
|
|
if (lastState == GateState.SignalPending)
|
|
{
|
|
this.state = GateState.Signalled;
|
|
return true;
|
|
}
|
|
|
|
if (lastState != GateState.Locked)
|
|
{
|
|
ThrowInvalidSignalGateState();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// This is factored out to allow Signal and Unlock to be inlined.
|
|
void ThrowInvalidSignalGateState()
|
|
{
|
|
throw Fx.Exception.AsError(new InvalidOperationException(InternalSR.InvalidSemaphoreExit));
|
|
}
|
|
|
|
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)]
|
|
class SignalGate<T> : SignalGate
|
|
{
|
|
T result;
|
|
|
|
public SignalGate()
|
|
: base()
|
|
{
|
|
}
|
|
|
|
public bool Signal(T result)
|
|
{
|
|
this.result = result;
|
|
return Signal();
|
|
}
|
|
|
|
public bool Unlock(out T result)
|
|
{
|
|
if (Unlock())
|
|
{
|
|
result = this.result;
|
|
return true;
|
|
}
|
|
|
|
result = default(T);
|
|
return false;
|
|
}
|
|
}
|
|
}
|