Use ThreadPool.WaitForSingleObject for SIGUSR1

This commit is contained in:
Jordan
2023-06-19 05:16:40 -04:00
parent 12319f5471
commit 41a805648f
3 changed files with 21 additions and 34 deletions
@@ -8,7 +8,6 @@ using Mono.Unix;
using Mono.Unix.Native;
using Tgstation.Server.Host.Core;
using Tgstation.Server.Host.Utils;
namespace Tgstation.Server.Host.System
{
@@ -17,21 +16,11 @@ namespace Tgstation.Server.Host.System
/// </summary>
sealed class PosixSignalHandler : IHostedService, IDisposable
{
/// <summary>
/// Check for signals each time this amount of milliseconds pass.
/// </summary>
const int CheckDelayMs = 250;
/// <summary>
/// The <see cref="IServerControl"/> for the <see cref="PosixSignalHandler"/>.
/// </summary>
readonly IServerControl serverControl;
/// <summary>
/// The <see cref="IAsyncDelayer"/> for the <see cref="PosixSignalHandler"/>.
/// </summary>
readonly IAsyncDelayer asyncDelayer;
/// <summary>
/// The <see cref="ILogger"/> for the <see cref="PosixSignalHandler"/>.
/// </summary>
@@ -51,12 +40,10 @@ namespace Tgstation.Server.Host.System
/// Initializes a new instance of the <see cref="PosixSignalHandler"/> class.
/// </summary>
/// <param name="serverControl">The value of <see cref="serverControl"/>.</param>
/// <param name="asyncDelayer">The value of <see cref="asyncDelayer"/>.</param>
/// <param name="logger">The value of <see cref="logger"/>.</param>
public PosixSignalHandler(IServerControl serverControl, IAsyncDelayer asyncDelayer, ILogger<PosixSignalHandler> logger)
public PosixSignalHandler(IServerControl serverControl, ILogger<PosixSignalHandler> logger)
{
this.serverControl = serverControl ?? throw new ArgumentNullException(nameof(serverControl));
this.asyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer));
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
cancellationTokenSource = new CancellationTokenSource();
@@ -100,17 +87,23 @@ namespace Tgstation.Server.Host.System
logger.LogTrace("Started SignalChecker");
using var unixSignal = new UnixSignal(Signum.SIGUSR1);
if (!unixSignal.IsSet)
{
logger.LogTrace("Waiting for SIGUSR1...");
var cancellationToken = cancellationTokenSource.Token;
while (!unixSignal.IsSet)
await asyncDelayer.Delay(TimeSpan.FromMilliseconds(CheckDelayMs), cancellationToken);
logger.LogTrace("Waiting for SIGUSR1...");
var cancellationToken = cancellationTokenSource.Token;
logger.LogTrace("SIGUSR1 received!");
var tcs = new TaskCompletionSource();
using (cancellationToken.Register(() => tcs.TrySetCanceled(cancellationToken)))
{
ThreadPool.RegisterWaitForSingleObject(
unixSignal,
(o, timeout) => tcs.TrySetResult(),
null,
Timeout.Infinite,
true);
await tcs.Task;
}
else
logger.LogDebug("SIGUSR1 has already been sent");
logger.LogTrace("SIGUSR1 received!");
logger.LogTrace("Triggering graceful shutdown...");
await serverControl.GracefulShutdown();
@@ -9,7 +9,6 @@ using Moq;
using Tgstation.Server.Host.Core;
using Tgstation.Server.Host.Extensions;
using Tgstation.Server.Host.System;
using Tgstation.Server.Host.Utils;
namespace Tgstation.Server.Host.Tests.Signals
{
@@ -25,9 +24,7 @@ namespace Tgstation.Server.Host.Tests.Signals
.Callback(() => tcs.SetResult())
.Returns(Task.CompletedTask);
var mockAsyncDelayer = new Mock<IAsyncDelayer>();
mockAsyncDelayer.Setup(x => x.Delay(It.IsAny<TimeSpan>(), It.IsAny<CancellationToken>())).Returns(Task.CompletedTask);
using var signalHandler = new PosixSignalHandler(mockServerControl.Object, mockAsyncDelayer.Object, Mock.Of<ILogger<PosixSignalHandler>>());
using var signalHandler = new PosixSignalHandler(mockServerControl.Object, Mock.Of<ILogger<PosixSignalHandler>>());
Assert.IsFalse(tcs.Task.IsCompleted);
@@ -43,7 +40,7 @@ namespace Tgstation.Server.Host.Tests.Signals
await signalHandler.StopAsync(default).WithToken(cts.Token);
Assert.IsFalse(tcs.Task.IsCompleted);
using var signalHandler2 = new PosixSignalHandler(mockServerControl.Object, mockAsyncDelayer.Object, Mock.Of<ILogger<PosixSignalHandler>>());
using var signalHandler2 = new PosixSignalHandler(mockServerControl.Object, Mock.Of<ILogger<PosixSignalHandler>>());
await signalHandler2.StartAsync(default);
using var cts2 = new CancellationTokenSource(TimeSpan.FromSeconds(20));
@@ -20,15 +20,12 @@ namespace Tgstation.Server.Host.System.Tests
[TestMethod]
public void TestConstruction()
{
Assert.ThrowsException<ArgumentNullException>(() => new PosixSignalHandler(null, null, null));
Assert.ThrowsException<ArgumentNullException>(() => new PosixSignalHandler(null, null));
var mockServerControl = Mock.Of<IServerControl>();
Assert.ThrowsException<ArgumentNullException>(() => new PosixSignalHandler(mockServerControl, null, null));
Assert.ThrowsException<ArgumentNullException>(() => new PosixSignalHandler(mockServerControl, null));
var mockAsyncDelayer = Mock.Of<IAsyncDelayer>();
Assert.ThrowsException<ArgumentNullException>(() => new PosixSignalHandler(mockServerControl, mockAsyncDelayer, null));
new PosixSignalHandler(mockServerControl, mockAsyncDelayer, Mock.Of<ILogger<PosixSignalHandler>>()).Dispose();
new PosixSignalHandler(mockServerControl, Mock.Of<ILogger<PosixSignalHandler>>()).Dispose();
}
[TestMethod]