public void Dispose_Idempotent(PosixSignal signal) { PosixSignalRegistration registration = PosixSignalRegistration.Create(signal, ctx => { }); registration.Dispose(); registration.Dispose(); }
public void SignalHandlerCalledForKnownSignals(PosixSignal s) { RemoteExecutor.Invoke(signalStr => { PosixSignal signal = Enum.Parse <PosixSignal>(signalStr); using SemaphoreSlim semaphore = new(0); using var _ = PosixSignalRegistration.Create(signal, ctx => { Assert.Equal(signal, ctx.Signal); // Ensure signal doesn't cause the process to terminate. ctx.Cancel = true; semaphore.Release(); }); // Use 'kill' command with signal name to validate the signal pal mapping. string sigArg = signalStr.StartsWith("SIG") ? signalStr.Substring(3) : signalStr; using var process = Process.Start(new ProcessStartInfo { FileName = "/bin/sh", // Use a shell because not all platforms include a 'kill' executable. ArgumentList = { "-c", $"kill -s {sigArg} {Environment.ProcessId.ToString()}" } }); process.WaitForExit(); Assert.Equal(0, process.ExitCode); bool entered = semaphore.Wait(SuccessTimeout); Assert.True(entered); }, s.ToString()).Dispose(); }
private static PosixSignalRegistration Register(PosixSignal signal, Action <PosixSignalContext> handler) { int signo = Interop.Sys.GetPlatformSignalNumber(signal); if (signo == 0) { throw new PlatformNotSupportedException(); } var token = new Token(signal, signo, handler); var registration = new PosixSignalRegistration(token); lock (s_registrations) { if (!s_registrations.TryGetValue(signo, out HashSet <Token>?tokens)) { s_registrations[signo] = tokens = new HashSet <Token>(); } if (tokens.Count == 0 && !Interop.Sys.EnablePosixSignalHandling(signo)) { Interop.CheckIo(-1); } tokens.Add(token); } return(registration); }
public void Constructor(PosixSignal value) { var ctx = new PosixSignalContext(value); Assert.Equal(value, ctx.Signal); Assert.False(ctx.Cancel); }
public static PosixSignalRegistration Create(PosixSignal signal, Action <PosixSignalContext> handler) { if (handler is null) { throw new ArgumentNullException(nameof(handler)); } return(Register(signal, handler)); }
public static partial PosixSignalRegistration Create(PosixSignal signal, Action <PosixSignalContext> handler) { if (handler is null) { throw new ArgumentNullException(nameof(handler)); } throw new PlatformNotSupportedException(); }
public void SignalHandlerNotCalledWhenFinalized() { PosixSignal signal = PosixSignal.SIGCONT; CreateDanglingRegistration(); GC.Collect(); GC.WaitForPendingFinalizers(); kill(signal); Thread.Sleep(100);
public void SignalHandlerNotCalledWhenDisposed() { PosixSignal signal = PosixSignal.SIGCONT; PosixSignalRegistration.Create(signal, ctx => { Assert.False(true, "Signal handler was called."); }).Dispose(); kill(signal); Thread.Sleep(100); }
private static int OnPosixSignal(int signo, PosixSignal signal) { Token[]? tokens = null; lock (s_registrations) { if (s_registrations.TryGetValue(signo, out HashSet <Token>?registrations)) { tokens = new Token[registrations.Count]; registrations.CopyTo(tokens); } } if (tokens is null) { return(0); } Debug.Assert(tokens.Length != 0); // This is called on the native signal handling thread. We need to move to another thread so // signal handling is not blocked. Otherwise we may get deadlocked when the handler depends // on work triggered from the signal handling thread. switch (signal) { case PosixSignal.SIGINT: case PosixSignal.SIGQUIT: case PosixSignal.SIGTERM: // For terminate/interrupt signals we use a dedicated Thread in case the ThreadPool is saturated. new Thread(HandleSignal) { IsBackground = true, Name = ".NET Signal Handler" }.UnsafeStart((signo, tokens)); break; default: ThreadPool.UnsafeQueueUserWorkItem(HandleSignal, (signo, tokens)); break; } return(1);
public void SignalHandlerCalledForRawSignals(PosixSignal s) { RemoteExecutor.Invoke((signalStr) => { PosixSignal signal = Enum.Parse <PosixSignal>(signalStr); using SemaphoreSlim semaphore = new(0); using var _ = PosixSignalRegistration.Create(signal, ctx => { Assert.Equal(signal, ctx.Signal); // Ensure signal doesn't cause the process to terminate. ctx.Cancel = true; semaphore.Release(); }); kill(signal); bool entered = semaphore.Wait(SuccessTimeout); Assert.True(entered); }, s.ToString()).Dispose(); }
public void SignalHandlerWorksForSecondRegistration() { PosixSignal signal = PosixSignal.SIGCONT; for (int i = 0; i < 2; i++) { using SemaphoreSlim semaphore = new(0); using var _ = PosixSignalRegistration.Create(signal, ctx => { Assert.Equal(signal, ctx.Signal); // Ensure signal doesn't cause the process to terminate. ctx.Cancel = true; semaphore.Release(); }); kill(signal); bool entered = semaphore.Wait(SuccessTimeout); Assert.True(entered); } }
public static partial PosixSignalRegistration Create(PosixSignal signal, Action <PosixSignalContext> handler);
internal static partial int GetPlatformSignalNumber(PosixSignal signal);
[DynamicDependency("#ctor")] // Prevent the private ctor and the IDisposable implementation from getting linked away private static PosixSignalRegistration Register(PosixSignal signal, Action <PosixSignalContext> handler) => throw new PlatformNotSupportedException();
/// <summary> /// Initializes a new instance of the <see cref="PosixSignalContext"/> class. /// </summary> public PosixSignalContext(PosixSignal signal) => Signal = signal;
public static PosixSignalRegistration Create(PosixSignal signal, Action <PosixSignalContext> handler) { ArgumentNullException.ThrowIfNull(handler); return(Register(signal, handler)); }
public static PosixSignalRegistration Create(PosixSignal signal, Action <PosixSignalContext> handler !!) =>
public void Create_InvalidSignal_Throws(PosixSignal signal) { Assert.Throws <PlatformNotSupportedException>(() => PosixSignalRegistration.Create(signal, ctx => { })); }
public void Create_UninstallableSignal_Throws(PosixSignal signal) { Assert.Throws <IOException>(() => PosixSignalRegistration.Create(signal, ctx => { })); }
public void Create_ValidSignal_Success(PosixSignal signal) { PosixSignalRegistration.Create(signal, ctx => { }).Dispose(); }
internal static extern int GetPlatformSignalNumber(PosixSignal signal);
public Token(PosixSignal signal, Action <PosixSignalContext> handler) { Signal = signal; Handler = handler; }