tgstation-server 6.12.0
The /tg/station 13 server suite
Loading...
Searching...
No Matches
PosixSignalChecker.cs
Go to the documentation of this file.
1using System;
2using System.Threading;
3using System.Threading.Tasks;
4
5using Microsoft.Extensions.Logging;
6
7using Mono.Unix;
8using Mono.Unix.Native;
9
11
13{
18 {
22 readonly ILogger<PosixSignalChecker> logger;
23
28 public PosixSignalChecker(ILogger<PosixSignalChecker> logger)
29 {
30 this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
31 }
32
34 public async ValueTask CheckSignals(Func<string?, (int, Task)> startChild, CancellationToken cancellationToken)
35 {
36 var (childPid, _) = startChild?.Invoke(null) ?? throw new ArgumentNullException(nameof(startChild));
37 var signalTcs = new TaskCompletionSource<Signum>();
38 async Task<Signum?> CheckSignal(Signum signum)
39 {
40 try
41 {
42 using var unixSignal = new UnixSignal(signum);
43 if (!unixSignal.IsSet)
44 {
45 logger.LogTrace("Waiting for {signum}...", signum);
46 while (!unixSignal.IsSet)
47 await Task.Delay(TimeSpan.FromMilliseconds(250), cancellationToken);
48
49 logger.LogTrace("{signum} received!", signum);
50 }
51 else
52 logger.LogDebug("{signum} has already been sent", signum);
53
54 signalTcs.TrySetResult(signum);
55 }
56 catch (OperationCanceledException)
57 {
58 }
59
60 return signum;
61 }
62
63 var tasks = new[]
64 {
65 CheckSignal(Signum.SIGUSR1),
66 CheckSignal(Signum.SIGUSR2),
67 };
68 var completedTask = await Task.WhenAny(tasks);
69 if (cancellationToken.IsCancellationRequested)
70 {
71 await Task.WhenAll(tasks);
72 return;
73 }
74
75 var signalReceived = await completedTask;
76 logger.LogInformation("Received {signalReceived}, forwarding to main TGS process!", signalReceived);
77 var result = Syscall.kill(childPid, signalReceived.Value);
78 if (result != 0)
79 logger.LogWarning(
80 new UnixIOException(Stdlib.GetLastError()),
81 "Failed to forward {signalReceived}!",
82 signalReceived);
83
84 // forward the other signal if necessary
85 await Task.WhenAll(tasks);
86 if (cancellationToken.IsCancellationRequested)
87 return;
88
89 var otherTask = tasks[0] == completedTask
90 ? tasks[1]
91 : tasks[0];
92
93 signalReceived = await otherTask;
94 logger.LogInformation("Received {signalReceived}, forwarding to main TGS process!", signalReceived);
95 result = Syscall.kill(childPid, signalReceived.Value);
96 if (result != 0)
97 logger.LogWarning(
98 new UnixIOException(Stdlib.GetLastError()),
99 "Failed to forward {signalReceived}!",
100 signalReceived);
101 }
102 }
103}
ISignalChecker for checking POSIX signals.
readonly ILogger< PosixSignalChecker > logger
The ILogger for the PosixSignalChecker.
async ValueTask CheckSignals(Func< string?,(int, Task)> startChild, CancellationToken cancellationToken)
PosixSignalChecker(ILogger< PosixSignalChecker > logger)
Initializes a new instance of the PosixSignalChecker class.
For relaying signals received to the host process.