Files
wx-win-agent/node-agent/WxAgent.Core/InterprocessCommandGate.cs
T

59 lines
1.6 KiB
C#

namespace WxAgent.Core;
/// <summary>Serializes commands locally and across processes; the OS releases the file handle after a crash.</summary>
public sealed class InterprocessCommandGate : IDisposable
{
private readonly SemaphoreSlim _local = new(1, 1);
private readonly string _path;
private FileStream? _lease;
public InterprocessCommandGate(string path)
{
_path = Path.GetFullPath(path);
Directory.CreateDirectory(Path.GetDirectoryName(_path)!);
}
public async Task WaitAsync(CancellationToken cancellationToken)
{
await _local.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
while (true)
{
cancellationToken.ThrowIfCancellationRequested();
try
{
_lease = new FileStream(_path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
return;
}
catch (IOException exception) when ((exception.HResult & 0xffff) is 11 or 32 or 33)
{
// EAGAIN on Unix; sharing/lock violation on Windows. Other I/O errors must surface.
await Task.Delay(50, cancellationToken).ConfigureAwait(false);
}
}
}
catch
{
_local.Release();
throw;
}
}
public void Release()
{
try { _lease?.Dispose(); }
finally
{
_lease = null;
_local.Release();
}
}
public void Dispose()
{
_lease?.Dispose();
_local.Dispose();
}
}