From bc5b5f9e96eca855b23adbdc852254081fc6784a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 20:08:27 -0400 Subject: [PATCH] Fix Mono.Posix loading on Windows host watchdog --- .../SignalChecker.cs | 92 +++++++++++++++++++ .../Watchdog.cs | 89 ++++++------------ 2 files changed, 120 insertions(+), 61 deletions(-) create mode 100644 src/Tgstation.Server.Host.Watchdog/SignalChecker.cs diff --git a/src/Tgstation.Server.Host.Watchdog/SignalChecker.cs b/src/Tgstation.Server.Host.Watchdog/SignalChecker.cs new file mode 100644 index 0000000000..3be780fb39 --- /dev/null +++ b/src/Tgstation.Server.Host.Watchdog/SignalChecker.cs @@ -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 +{ + /// + /// Helper for checking POSIX signals. + /// + static class SignalChecker + { + /// + /// Forwards certain signals to a given . + /// + /// The to write to. + /// The of the process to forward signals to. + /// The for the operation. + /// A representing the running operation. + public static async Task CheckSignals(ILogger logger, int childPid, CancellationToken cancellationToken) + { + var signalTcs = new TaskCompletionSource(); + async Task 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); + } + } +} diff --git a/src/Tgstation.Server.Host.Watchdog/Watchdog.cs b/src/Tgstation.Server.Host.Watchdog/Watchdog.cs index d8a1d580ed..1afd2cad85 100644 --- a/src/Tgstation.Server.Host.Watchdog/Watchdog.cs +++ b/src/Tgstation.Server.Host.Watchdog/Watchdog.cs @@ -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(); - 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!");