Beispiel #1
0
        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);
        }
Beispiel #5
0
        public static PosixSignalRegistration Create(PosixSignal signal, Action <PosixSignalContext> handler)
        {
            if (handler is null)
            {
                throw new ArgumentNullException(nameof(handler));
            }

            return(Register(signal, handler));
        }
Beispiel #6
0
        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);
            }
        }
Beispiel #12
0
 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();
Beispiel #15
0
 /// <summary>
 /// Initializes a new instance of the <see cref="PosixSignalContext"/> class.
 /// </summary>
 public PosixSignalContext(PosixSignal signal) => Signal = signal;
Beispiel #16
0
        public static PosixSignalRegistration Create(PosixSignal signal, Action <PosixSignalContext> handler)
        {
            ArgumentNullException.ThrowIfNull(handler);

            return(Register(signal, handler));
        }
Beispiel #17
0
 public static PosixSignalRegistration Create(PosixSignal signal, Action <PosixSignalContext> handler !!) =>
Beispiel #18
0
 public void Create_InvalidSignal_Throws(PosixSignal signal)
 {
     Assert.Throws <PlatformNotSupportedException>(() => PosixSignalRegistration.Create(signal, ctx => { }));
 }
Beispiel #19
0
 public void Create_UninstallableSignal_Throws(PosixSignal signal)
 {
     Assert.Throws <IOException>(() => PosixSignalRegistration.Create(signal, ctx => { }));
 }
Beispiel #20
0
 public void Create_ValidSignal_Success(PosixSignal signal)
 {
     PosixSignalRegistration.Create(signal, ctx => { }).Dispose();
 }
Beispiel #21
0
 internal static extern int GetPlatformSignalNumber(PosixSignal signal);
Beispiel #22
0
 public Token(PosixSignal signal, Action <PosixSignalContext> handler)
 {
     Signal  = signal;
     Handler = handler;
 }