Fix Mono.Posix loading on Windows host watchdog

This commit is contained in:
Jordan Dominion
2023-06-23 20:08:27 -04:00
parent 85f8c9131b
commit bc5b5f9e96
2 changed files with 120 additions and 61 deletions
@@ -0,0 +1,92 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Mono.Unix;
using Mono.Unix.Native;
namespace Tgstation.Server.Host.Watchdog
{
/// <summary>
/// Helper for checking POSIX signals.
/// </summary>
static class SignalChecker
{
/// <summary>
/// Forwards certain signals to a given <paramref name="childPid"/>.
/// </summary>
/// <param name="logger">The <see cref="ILogger"/> to write to.</param>
/// <param name="childPid">The <see cref="System.Diagnostics.Process.Id"/> of the process to forward signals to.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
/// <returns>A <see cref="Task"/> representing the running operation.</returns>
public static async Task CheckSignals(ILogger logger, int childPid, CancellationToken cancellationToken)
{
var signalTcs = new TaskCompletionSource<Signum>();
async Task<Signum?> CheckSignal(Signum signum)
{
try
{
using var unixSignal = new UnixSignal(signum);
if (!unixSignal.IsSet)
{
logger.LogTrace("Waiting for {signum}...", signum);
while (!unixSignal.IsSet)
await Task.Delay(TimeSpan.FromMilliseconds(250), cancellationToken);
logger.LogTrace("{signum} received!", signum);
}
else
logger.LogDebug("{signum} has already been sent", signum);
signalTcs.TrySetResult(signum);
}
catch (OperationCanceledException)
{
}
return signum;
}
var tasks = new[]
{
CheckSignal(Signum.SIGUSR1),
CheckSignal(Signum.SIGUSR2),
};
var completedTask = await Task.WhenAny(tasks);
if (cancellationToken.IsCancellationRequested)
{
await Task.WhenAll(tasks);
return;
}
var signalReceived = await completedTask;
logger.LogInformation("Received {signalReceived}, forwarding to main TGS process!", signalReceived);
var result = Syscall.kill(childPid, signalReceived.Value);
if (result != 0)
logger.LogWarning(
new UnixIOException(Stdlib.GetLastError()),
"Failed to forward {signalReceived}!",
signalReceived);
// forward the other signal if necessary
await Task.WhenAll(tasks);
if (cancellationToken.IsCancellationRequested)
return;
var otherTask = tasks[0] == completedTask
? tasks[1]
: tasks[0];
signalReceived = await otherTask;
logger.LogInformation("Received {signalReceived}, forwarding to main TGS process!", signalReceived);
result = Syscall.kill(childPid, signalReceived.Value);
if (result != 0)
logger.LogWarning(
new UnixIOException(Stdlib.GetLastError()),
"Failed to forward {signalReceived}!",
signalReceived);
}
}
}
+28 -61
View File
@@ -11,9 +11,6 @@ using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Mono.Unix;
using Mono.Unix.Native;
using Tgstation.Server.Host.Common;
namespace Tgstation.Server.Host.Watchdog
@@ -71,7 +68,8 @@ namespace Tgstation.Server.Host.Watchdog
{
// VS special tactics
// just copy the shit where it belongs
Directory.Delete(assemblyStoragePath, true);
if (Directory.Exists(assemblyStoragePath))
Directory.Delete(assemblyStoragePath, true);
Directory.CreateDirectory(defaultAssemblyPath);
var sourcePath = "../../../../Tgstation.Server.Host/bin/Debug/net6.0";
@@ -128,8 +126,8 @@ namespace Tgstation.Server.Host.Watchdog
if (runConfigure)
{
logger.LogInformation("Running configuration check and wizard if necessary...");
arguments.Add("General:SetupWizardMode=Only");
logger.LogInformation("Running configuration check and wizard...");
arguments.Add("--General:SetupWizardMode=Only");
}
arguments.AddRange(args);
@@ -179,61 +177,19 @@ namespace Tgstation.Server.Host.Watchdog
}))
{
var processTask = tcs.Task;
while (!processTask.IsCompleted)
using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
var checkerTask = isWindows
? Task.CompletedTask
: SignalChecker.CheckSignals(logger, childPid, cts.Token);
try
{
var signalTcs = new TaskCompletionSource<Signum>();
using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
async Task CheckSignal(Signum signum)
{
if (isWindows)
return;
try
{
using var unixSignal = new UnixSignal(signum);
if (!unixSignal.IsSet)
{
logger.LogTrace("Waiting for {signum}...", signum);
while (!unixSignal.IsSet)
await Task.Delay(TimeSpan.FromMilliseconds(250), cts.Token);
logger.LogTrace("{signum} received!", signum);
}
else
logger.LogDebug("{signum} has already been sent", signum);
signalTcs.TrySetResult(signum);
}
catch (OperationCanceledException)
{
}
}
var checkerTask = Task.WhenAll(
CheckSignal(Signum.SIGUSR1),
CheckSignal(Signum.SIGUSR2));
try
{
var signalTask = signalTcs.Task;
var completedTask = await Task.WhenAny(processTask, signalTask);
if (completedTask == signalTask)
{
var signalReceived = await signalTask;
logger.LogInformation("Received {signalReceived}, forwarding to main TGS process!", signalReceived);
var result = Syscall.kill(childPid, signalReceived);
if (result != 0)
logger.LogWarning(
new UnixIOException(Stdlib.GetLastError()),
"Failed to forward {signalReceived}!",
signalReceived);
}
}
finally
{
cts.Cancel();
await checkerTask;
}
await processTask;
}
finally
{
cts.Cancel();
await checkerTask;
}
}
}
@@ -252,8 +208,19 @@ namespace Tgstation.Server.Host.Watchdog
process.WaitForExit();
}
}
catch (InvalidOperationException)
catch (InvalidOperationException ex2)
{
logger.LogWarning(ex2, "Error killing host process!");
}
try
{
if (File.Exists(updateDirectory))
File.Delete(updateDirectory);
}
catch (Exception ex2)
{
logger.LogWarning(ex2, "Error deleting comms file!");
}
logger.LogInformation("Host exited!");