Files
RobustToolbox/Robust.Shared/Asynchronous/RobustSynchronizationContext.cs
2022-12-20 22:46:30 +01:00

79 lines
2.3 KiB
C#

using System;
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
using Robust.Shared.Exceptions;
namespace Robust.Shared.Asynchronous
{
internal sealed class RobustSynchronizationContext : SynchronizationContext
{
// Used only on release.
// ReSharper disable once NotAccessedField.Local
private readonly IRuntimeLog _runtimeLog;
public RobustSynchronizationContext(IRuntimeLog runtimeLog)
{
_runtimeLog = runtimeLog;
var channel = Channel.CreateUnbounded<Mail>(new UnboundedChannelOptions
{
SingleReader = true,
SingleWriter = false,
// For unblocking continuations.
AllowSynchronousContinuations = true
});
_channelReader = channel.Reader;
_channelWriter = channel.Writer;
}
private readonly ChannelReader<Mail> _channelReader;
private readonly ChannelWriter<Mail> _channelWriter;
public override void Send(SendOrPostCallback d, object? state)
{
if (Current != this)
{
// Being invoked from another thread?
// If this not implemented exception starts being a problem I'll fix it but right now I'd rather err on the side of caution,
// so that if cross thread usage is required I have a test case, instead of a data race.
throw new NotImplementedException();
}
d(state);
}
public override void Post(SendOrPostCallback d, object? state)
{
_channelWriter.TryWrite(new Mail(d, state));
}
public void ProcessPendingTasks()
{
while (_channelReader.TryRead(out var task))
{
#if EXCEPTION_TOLERANCE
try
#endif
{
task.Callback(task.State);
}
#if EXCEPTION_TOLERANCE
catch (Exception e)
{
_runtimeLog.LogException(e, "Async Queued Callback");
}
#endif
}
}
public ValueTask<bool> WaitOnPendingTasks()
{
return _channelReader.WaitToReadAsync();
}
private record struct Mail(SendOrPostCallback Callback, object? State);
}
}