// Copyright Epic Games, Inc. All Rights Reserved.
using System.Threading;
using System.Threading.Tasks;
namespace EpicGames.Core
{
///
/// Wrapper to allow awaiting an event being signalled, similar to an AutoResetEvent.
///
public class AsyncEvent
{
///
/// Completion source to wait on
///
TaskCompletionSource _source = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
///
/// Legacy name for .
///
public void Set() => Pulse();
///
/// Pulse the event, allowing any captured copies of the task to continue.
///
public void Pulse()
{
for (; ; )
{
TaskCompletionSource prevSource = _source;
if (prevSource.Task.IsCompleted)
{
// The task source is latched or has been set from another thread. Either way behaves identically wrt the contract of this method.
break;
}
if (Interlocked.CompareExchange(ref _source, new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously), prevSource) == prevSource)
{
prevSource.TrySetResult(true);
break;
}
}
}
///
/// Resets an event which is latched to the set state.
///
public void Reset()
{
for (; ; )
{
TaskCompletionSource prevSource = _source;
if (!prevSource.Task.IsCompleted)
{
break;
}
else if (Interlocked.CompareExchange(ref _source, new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously), prevSource) == prevSource)
{
break;
}
}
}
///
/// Move the task to completed without returning it to an unset state. A call to Reset() is required to clear it.
///
public void Latch()
{
_source.TrySetResult(true);
}
///
/// Determines if this event is set
///
/// True if the event is set
public bool IsSet()
{
return _source.Task.IsCompleted;
}
///
/// Waits for this event to be set
///
public Task Task => _source.Task;
}
}