Move PosixSignalRegistration to corelib (#55433)
authorStephen Toub <stoub@microsoft.com>
Sun, 11 Jul 2021 18:13:35 +0000 (14:13 -0400)
committerGitHub <noreply@github.com>
Sun, 11 Jul 2021 18:13:35 +0000 (14:13 -0400)
* Move PosixSignalRegistration to corelib

* Fix trimming issue on mobile targets

19 files changed:
src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs
src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/PosixSignal.cs [new file with mode: 0644]
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/PosixSignalContext.cs [new file with mode: 0644]
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/PosixSignalRegistration.PlatformNotSupported.cs [new file with mode: 0644]
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/PosixSignalRegistration.Unix.cs [new file with mode: 0644]
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/PosixSignalRegistration.Windows.cs [new file with mode: 0644]
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/PosixSignalRegistration.cs [new file with mode: 0644]
src/libraries/System.Runtime.InteropServices/src/Resources/Strings.resx
src/libraries/System.Runtime.InteropServices/src/System.Runtime.InteropServices.csproj
src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/PosixSignal.cs [deleted file]
src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/PosixSignalContext.cs [deleted file]
src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/PosixSignalRegistration.Unix.cs [deleted file]
src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/PosixSignalRegistration.Unsupported.cs [deleted file]
src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/PosixSignalRegistration.Windows.cs [deleted file]
src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/PosixSignalRegistration.cs [deleted file]
src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.Tests.csproj
src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/PosixSignalRegistrationTests.Browser.cs [deleted file]
src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/PosixSignalRegistrationTests.Unix.cs

index e11da7e8d4d93b8b6c9a866984e60eaf7a9b6d4d..90f21d02f5c49b5150168c5aa6cf937b5f5ac583 100644 (file)
@@ -37,7 +37,8 @@ namespace System
         public static bool IsSolaris => RuntimeInformation.IsOSPlatform(OSPlatform.Create("SOLARIS"));
         public static bool IsBrowser => RuntimeInformation.IsOSPlatform(OSPlatform.Create("BROWSER"));
         public static bool IsNotBrowser => !IsBrowser;
-        public static bool IsNotMobile => IsNotBrowser && !IsMacCatalyst && !IsiOS && !IstvOS && !IsAndroid;
+        public static bool IsMobile => IsBrowser || IsMacCatalyst || IsiOS || IstvOS || IsAndroid;
+        public static bool IsNotMobile => !IsMobile;
         public static bool IsNotNetFramework => !IsNetFramework;
 
         public static bool IsArmProcess => RuntimeInformation.ProcessArchitecture == Architecture.Arm;
index a1e270dbde97ddc5c57067a8b930b90adf595419..3dcfc2c7313a576a78b6669f342bb24a2135413b 100644 (file)
     <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\NFloat.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\OptionalAttribute.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\OutAttribute.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\PosixSignal.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\PosixSignalContext.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\PosixSignalRegistration.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\PreserveSigAttribute.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\ProgIdAttribute.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\SafeArrayRankMismatchException.cs" />
   </ItemGroup>
   <ItemGroup Condition="'$(IsMobileLike)' == 'true'">
     <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\Loader\AssemblyDependencyResolver.PlatformNotSupported.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\PosixSignalRegistration.PlatformNotSupported.cs" />
   </ItemGroup>
   <ItemGroup>
     <Compile Include="$(CommonPath)Interop\Windows\Advapi32\Interop.ActivityControl.cs">
     <Compile Include="$(CommonPath)Interop\Windows\Interop.OBJECT_ATTRIBUTES.cs">
       <Link>Common\Interop\Windows\Interop.OBJECT_ATTRIBUTES.cs</Link>
     </Compile>
+    <Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.SetConsoleCtrlHandler.cs">
+        <Link>Common\Interop\Windows\Interop.SetConsoleCtrlHandler.cs</Link>
+    </Compile>
     <Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.SetCurrentDirectory.cs">
       <Link>Common\Interop\Windows\Kernel32\Interop.SetCurrentDirectory.cs</Link>
     </Compile>
     <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\MemoryFailPoint.Windows.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\Marshal.Windows.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\NativeMemory.Windows.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\PosixSignalRegistration.Windows.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\StandardOleMarshalObject.Windows.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Security\SecureString.Windows.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Threading\LowLevelMonitor.Windows.cs" />
     <Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.GetPid.cs">
       <Link>Common\Interop\Unix\System.Native\Interop.GetPid.cs</Link>
     </Compile>
+    <Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.InitializeTerminalAndSignalHandling.cs"
+             Link="Common\Interop\Unix\Interop.InitializeTerminalAndSignalHandling.cs" />
+    <Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.PosixSignal.cs"
+             Link="Common\Interop\Unix\Interop.PosixSignal.cs" />
     <Compile Include="$(CommonPath)Interop\FreeBSD\Interop.Process.GetProcInfo.cs" Condition="'$(TargetsFreeBSD)' == 'true'"
              Link="Common\Interop\FreeBSD\Interop.Process.GetProcInfo.cs" />
     <Compile Include="$(CommonPath)Interop\BSD\System.Native\Interop.Sysctl.cs" Condition="'$(TargetsFreeBSD)' == 'true'"
     <Compile Include="$(MSBuildThisFileDirectory)System\IO\DriveInfoInternal.Unix.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\IO\PersistedFiles.Unix.cs" />
   </ItemGroup>
+  <ItemGroup Condition="'$(TargetsUnix)' == 'true' and '$(IsMobileLike)' != 'true'">
+    <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\PosixSignalRegistration.Unix.cs" />
+  </ItemGroup>
   <ItemGroup Condition="'$(TargetsBrowser)' == 'true'">
     <Compile Include="$(MSBuildThisFileDirectory)System\AppContext.Browser.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Environment.Browser.cs" />
diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/PosixSignal.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/PosixSignal.cs
new file mode 100644 (file)
index 0000000..e1f278f
--- /dev/null
@@ -0,0 +1,47 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Runtime.Versioning;
+
+namespace System.Runtime.InteropServices
+{
+    /// <summary>Specifies a POSIX signal number.</summary>
+    public enum PosixSignal
+    {
+        /// <summary>Hangup</summary>
+        SIGHUP = -1,
+
+        /// <summary>Interrupt</summary>
+        SIGINT = -2,
+
+        /// <summary>Quit</summary>
+        SIGQUIT = -3,
+
+        /// <summary>Termination</summary>
+        SIGTERM = -4,
+
+        /// <summary>Child stopped</summary>
+        [UnsupportedOSPlatform("windows")]
+        SIGCHLD = -5,
+
+        /// <summary>Continue if stopped</summary>
+        [UnsupportedOSPlatform("windows")]
+        SIGCONT = -6,
+
+        /// <summary>Window resized</summary>
+        [UnsupportedOSPlatform("windows")]
+        SIGWINCH = -7,
+
+        /// <summary>Terminal input for background process</summary>
+        [UnsupportedOSPlatform("windows")]
+        SIGTTIN = -8,
+
+        /// <summary>Terminal output for background process</summary>
+        [UnsupportedOSPlatform("windows")]
+        SIGTTOU = -9,
+
+        /// <summary>Stop typed at terminal</summary>
+        [UnsupportedOSPlatform("windows")]
+        SIGTSTP = -10
+    }
+}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/PosixSignalContext.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/PosixSignalContext.cs
new file mode 100644 (file)
index 0000000..cf73dd6
--- /dev/null
@@ -0,0 +1,26 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace System.Runtime.InteropServices
+{
+    /// <summary>
+    /// Provides data for a <see cref="PosixSignalRegistration"/> event.
+    /// </summary>
+    public sealed class PosixSignalContext
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="PosixSignalContext"/> class.
+        /// </summary>
+        public PosixSignalContext(PosixSignal signal) => Signal = signal;
+
+        /// <summary>
+        /// Gets the signal that occurred.
+        /// </summary>
+        public PosixSignal Signal { get; internal set; }
+
+        /// <summary>
+        /// Gets or sets a value that indicates whether to cancel the default handling of the signal. The default is <see langword="false"/>.
+        /// </summary>
+        public bool Cancel { get; set; }
+    }
+}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/PosixSignalRegistration.PlatformNotSupported.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/PosixSignalRegistration.PlatformNotSupported.cs
new file mode 100644 (file)
index 0000000..3ccc169
--- /dev/null
@@ -0,0 +1,25 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Diagnostics.CodeAnalysis;
+
+namespace System.Runtime.InteropServices
+{
+    public sealed partial class PosixSignalRegistration
+    {
+        private PosixSignalRegistration() { }
+
+        [DynamicDependency("#ctor")] // Prevent the private ctor and the IDisposable implementation from getting linked away
+        public static partial PosixSignalRegistration Create(PosixSignal signal, Action<PosixSignalContext> handler)
+        {
+            if (handler is null)
+            {
+                throw new ArgumentNullException(nameof(handler));
+            }
+
+            throw new PlatformNotSupportedException();
+        }
+
+        public partial void Dispose() { }
+    }
+}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/PosixSignalRegistration.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/PosixSignalRegistration.Unix.cs
new file mode 100644 (file)
index 0000000..f01b2de
--- /dev/null
@@ -0,0 +1,268 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Collections.Generic;
+using System.Threading;
+
+namespace System.Runtime.InteropServices
+{
+    public sealed partial class PosixSignalRegistration
+    {
+        private static volatile bool s_initialized;
+        private static readonly Dictionary<int, List<WeakReference<PosixSignalRegistration>?>> s_registrations = new();
+
+        private readonly Action<PosixSignalContext> _handler;
+        private readonly PosixSignal _signal;
+        private readonly int _signo;
+        private bool _registered;
+        private readonly object _gate = new object();
+
+        private PosixSignalRegistration(PosixSignal signal, int signo, Action<PosixSignalContext> handler)
+        {
+            _signal = signal;
+            _signo = signo;
+            _handler = handler;
+        }
+
+        public static partial PosixSignalRegistration Create(PosixSignal signal, Action<PosixSignalContext> handler)
+        {
+            if (handler == null)
+            {
+                throw new ArgumentNullException(nameof(handler));
+            }
+
+            int signo = Interop.Sys.GetPlatformSignalNumber(signal);
+            if (signo == 0)
+            {
+                throw new PlatformNotSupportedException();
+            }
+
+            PosixSignalRegistration registration = new PosixSignalRegistration(signal, signo, handler);
+            registration.Register();
+            return registration;
+        }
+
+        private unsafe void Register()
+        {
+            if (!s_initialized)
+            {
+                if (!Interop.Sys.InitializeTerminalAndSignalHandling())
+                {
+                    // We can't use Win32Exception because that causes a cycle with
+                    // Microsoft.Win32.Primitives.
+                    Interop.CheckIo(-1);
+                }
+
+                Interop.Sys.SetPosixSignalHandler(&OnPosixSignal);
+                s_initialized = true;
+            }
+
+            lock (s_registrations)
+            {
+                if (!s_registrations.TryGetValue(_signo, out List<WeakReference<PosixSignalRegistration>?>? signalRegistrations))
+                {
+                    signalRegistrations = new List<WeakReference<PosixSignalRegistration>?>();
+                    s_registrations.Add(_signo, signalRegistrations);
+                }
+
+                if (signalRegistrations.Count == 0)
+                {
+                    if (!Interop.Sys.EnablePosixSignalHandling(_signo))
+                    {
+                        // We can't use Win32Exception because that causes a cycle with
+                        // Microsoft.Win32.Primitives.
+                        Interop.CheckIo(-1);
+                    }
+                }
+
+                signalRegistrations.Add(new WeakReference<PosixSignalRegistration>(this));
+            }
+
+            _registered = true;
+        }
+
+        private bool CallHandler(PosixSignalContext context)
+        {
+            lock (_gate)
+            {
+                if (_registered)
+                {
+                    _handler(context);
+                    return true;
+                }
+
+                return false;
+            }
+        }
+
+        [UnmanagedCallersOnly]
+        private static int OnPosixSignal(int signo, PosixSignal signal)
+        {
+            PosixSignalRegistration?[]? registrations = GetRegistrations(signo);
+            if (registrations != null)
+            {
+                // 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.
+
+                // For terminate/interrupt signals we use a dedicated Thread
+                // in case the ThreadPool is saturated.
+                bool useDedicatedThread = signal == PosixSignal.SIGINT ||
+                                          signal == PosixSignal.SIGQUIT ||
+                                          signal == PosixSignal.SIGTERM;
+
+                if (useDedicatedThread)
+                {
+                    Thread handlerThread = new Thread(HandleSignal)
+                    {
+                        IsBackground = true,
+                        Name = ".NET Signal Handler"
+                    };
+                    handlerThread.UnsafeStart((signo, registrations));
+                }
+                else
+                {
+                    ThreadPool.UnsafeQueueUserWorkItem(HandleSignal, (signo, registrations));
+                }
+
+                return 1;
+            }
+
+            return 0;
+        }
+
+        private static PosixSignalRegistration?[]? GetRegistrations(int signo)
+        {
+            lock (s_registrations)
+            {
+                if (s_registrations.TryGetValue(signo, out List<WeakReference<PosixSignalRegistration>?>? signalRegistrations))
+                {
+                    if (signalRegistrations.Count != 0)
+                    {
+                        var registrations = new PosixSignalRegistration?[signalRegistrations.Count];
+                        bool hasRegistrations = false;
+                        bool pruneWeakReferences = false;
+
+                        for (int i = 0; i < signalRegistrations.Count; i++)
+                        {
+                            if (signalRegistrations[i]!.TryGetTarget(out PosixSignalRegistration? registration))
+                            {
+                                registrations[i] = registration;
+                                hasRegistrations = true;
+                            }
+                            else
+                            {
+                                // WeakReference no longer holds an object. PosixSignalRegistration got finalized.
+                                signalRegistrations[i] = null;
+                                pruneWeakReferences = true;
+                            }
+                        }
+
+                        if (pruneWeakReferences)
+                        {
+                            signalRegistrations.RemoveAll(item => item is null);
+                        }
+
+                        if (hasRegistrations)
+                        {
+                            return registrations;
+                        }
+                        else
+                        {
+                            Interop.Sys.DisablePosixSignalHandling(signo);
+                        }
+                    }
+                }
+                return null;
+            }
+        }
+
+        private static void HandleSignal(object? state)
+        {
+            HandleSignal(((int, PosixSignalRegistration?[]))state!);
+        }
+
+        private static void HandleSignal((int signo, PosixSignalRegistration?[]? registrations) state)
+        {
+            do
+            {
+                bool handlersCalled = false;
+                if (state.registrations != null)
+                {
+                    PosixSignalContext ctx = new(0);
+                    foreach (PosixSignalRegistration? registration in state.registrations)
+                    {
+                        if (registration != null)
+                        {
+                            // Different values for PosixSignal map to the same signo.
+                            // Match the PosixSignal value used when registering.
+                            ctx.Signal = registration._signal;
+                            if (registration.CallHandler(ctx))
+                            {
+                                handlersCalled = true;
+                            }
+                        }
+                    }
+
+                    if (ctx.Cancel)
+                    {
+                        return;
+                    }
+                }
+
+                if (Interop.Sys.HandleNonCanceledPosixSignal(state.signo, handlersCalled ? 0 : 1))
+                {
+                    return;
+                }
+
+                // HandleNonCanceledPosixSignal returns false when handlers got registered.
+                state.registrations = GetRegistrations(state.signo);
+            } while (true);
+        }
+
+        public partial void Dispose()
+        {
+            if (_registered)
+            {
+                lock (s_registrations)
+                {
+                    List<WeakReference<PosixSignalRegistration>?> signalRegistrations = s_registrations[_signo];
+                    bool pruneWeakReferences = false;
+                    for (int i = 0; i < signalRegistrations.Count; i++)
+                    {
+                        if (signalRegistrations[i]!.TryGetTarget(out PosixSignalRegistration? registration))
+                        {
+                            if (ReferenceEquals(this, registration))
+                            {
+                                signalRegistrations.RemoveAt(i);
+                                break;
+                            }
+                        }
+                        else
+                        {
+                            // WeakReference no longer holds an object. PosixSignalRegistration got finalized.
+                            signalRegistrations[i] = null;
+                            pruneWeakReferences = true;
+                        }
+                    }
+
+                    if (pruneWeakReferences)
+                    {
+                        signalRegistrations.RemoveAll(item => item is null);
+                    }
+
+                    if (signalRegistrations.Count == 0)
+                    {
+                        Interop.Sys.DisablePosixSignalHandling(_signo);
+                    }
+                }
+
+                // Synchronize with _handler invocations.
+                lock (_gate)
+                {
+                    _registered = false;
+                }
+            }
+        }
+    }
+}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/PosixSignalRegistration.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/PosixSignalRegistration.Windows.cs
new file mode 100644 (file)
index 0000000..d3e5405
--- /dev/null
@@ -0,0 +1,134 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Collections.Generic;
+using System.IO;
+
+namespace System.Runtime.InteropServices
+{
+    public sealed unsafe partial class PosixSignalRegistration
+    {
+        private static readonly HashSet<Token> s_handlers = new();
+
+        private Token? _token;
+
+        private PosixSignalRegistration(Token token) => _token = token;
+
+        private static object SyncObj => s_handlers;
+
+        public static partial PosixSignalRegistration Create(PosixSignal signal, Action<PosixSignalContext> handler)
+        {
+            if (handler is null)
+            {
+                throw new ArgumentNullException(nameof(handler));
+            }
+
+            lock (SyncObj)
+            {
+                switch (signal)
+                {
+                    case PosixSignal.SIGINT:
+                    case PosixSignal.SIGQUIT:
+                    case PosixSignal.SIGTERM:
+                    case PosixSignal.SIGHUP:
+                        break;
+
+                    default:
+                        throw new PlatformNotSupportedException();
+                }
+
+                if (s_handlers.Count == 0 &&
+                    !Interop.Kernel32.SetConsoleCtrlHandler(&HandlerRoutine, Add: true))
+                {
+                    throw Win32Marshal.GetExceptionForLastWin32Error();
+                }
+
+                var token = new Token(signal, handler);
+                s_handlers.Add(token);
+                return new PosixSignalRegistration(token);
+            }
+        }
+
+        public partial void Dispose()
+        {
+            lock (SyncObj)
+            {
+                if (_token is Token token)
+                {
+                    _token = null;
+
+                    s_handlers.Remove(token);
+                    if (s_handlers.Count == 0 &&
+                        !Interop.Kernel32.SetConsoleCtrlHandler(&HandlerRoutine, Add: false))
+                    {
+                        throw Win32Marshal.GetExceptionForLastWin32Error();
+                    }
+                }
+            }
+        }
+
+        [UnmanagedCallersOnly]
+        private static Interop.BOOL HandlerRoutine(int dwCtrlType)
+        {
+            PosixSignal signal;
+            switch (dwCtrlType)
+            {
+                case Interop.Kernel32.CTRL_C_EVENT:
+                    signal = PosixSignal.SIGINT;
+                    break;
+
+                case Interop.Kernel32.CTRL_BREAK_EVENT:
+                    signal = PosixSignal.SIGQUIT;
+                    break;
+
+                case Interop.Kernel32.CTRL_SHUTDOWN_EVENT:
+                    signal = PosixSignal.SIGTERM;
+                    break;
+
+                case Interop.Kernel32.CTRL_CLOSE_EVENT:
+                    signal = PosixSignal.SIGHUP;
+                    break;
+
+                default:
+                    return Interop.BOOL.FALSE;
+            }
+
+            List<Token>? tokens = null;
+            lock (SyncObj)
+            {
+                foreach (Token token in s_handlers)
+                {
+                    if (token.Signal == signal)
+                    {
+                        (tokens ??= new()).Add(token);
+                    }
+                }
+            }
+
+            if (tokens is null)
+            {
+                return Interop.BOOL.FALSE;
+            }
+
+            var context = new PosixSignalContext(signal);
+            foreach (Token handler in tokens)
+            {
+                handler.Handler(context);
+            }
+
+            return context.Cancel ? Interop.BOOL.TRUE : Interop.BOOL.FALSE;
+        }
+
+        private sealed class Token
+        {
+            public Token(PosixSignal signal, Action<PosixSignalContext> handler)
+            {
+                Signal = signal;
+                Handler = handler;
+            }
+
+            public PosixSignal Signal { get; }
+            public Action<PosixSignalContext> Handler { get; }
+        }
+    }
+}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/PosixSignalRegistration.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/PosixSignalRegistration.cs
new file mode 100644 (file)
index 0000000..fb2c675
--- /dev/null
@@ -0,0 +1,38 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.IO;
+using System.Runtime.Versioning;
+
+namespace System.Runtime.InteropServices
+{
+    /// <summary>Handles a <see cref="PosixSignal"/>.</summary>
+    public sealed partial class PosixSignalRegistration : IDisposable
+    {
+        /// <summary>Registers a <paramref name="handler"/> that is invoked when the <paramref name="signal"/> occurs.</summary>
+        /// <param name="signal">The signal to register for.</param>
+        /// <param name="handler">The handler that gets invoked.</param>
+        /// <returns>A <see cref="PosixSignalRegistration"/> instance that can be disposed to unregister the handler.</returns>
+        /// <exception cref="ArgumentNullException"><paramref name="handler"/> is <see langword="null"/>.</exception>
+        /// <exception cref="PlatformNotSupportedException"><paramref name="signal"/> is not supported by the platform.</exception>
+        /// <exception cref="IOException">An error occurred while setting up the signal handling or while installing the handler for the specified signal.</exception>
+        /// <remarks>
+        /// Raw values can be provided for <paramref name="signal"/> on Unix by casting them to <see cref="PosixSignal"/>.
+        /// Default handling of the signal can be canceled through <see cref="PosixSignalContext.Cancel"/>.
+        /// <see cref="PosixSignal.SIGINT"/> and <see cref="PosixSignal.SIGQUIT"/> can be canceled on both
+        /// Windows and on Unix platforms; <see cref="PosixSignal.SIGTERM"/> can only be canceled on Unix.
+        /// On Unix, terminal configuration can be canceled for <see cref="PosixSignal.SIGCHLD"/> and <see cref="PosixSignal.SIGCONT"/>.
+        /// </remarks>
+        [UnsupportedOSPlatform("android")]
+        [UnsupportedOSPlatform("browser")]
+        [UnsupportedOSPlatform("ios")]
+        [UnsupportedOSPlatform("maccatalyst")]
+        [UnsupportedOSPlatform("tvos")]
+        public static partial PosixSignalRegistration Create(PosixSignal signal, Action<PosixSignalContext> handler);
+
+        /// <summary>Unregister the handler.</summary>
+        public partial void Dispose();
+
+        ~PosixSignalRegistration() => Dispose();
+    }
+}
index d7644789f28c21e35fa22c151ffe1902f625a4b6..08d7e045a580f5c5e02c58e41a2c2fe44b3191eb 100644 (file)
   <data name="ArgumentOutOfRange_FileLengthTooBig" xml:space="preserve">
     <value>Specified file length was too large for the file system.</value>
   </data>
-  <data name="IO_AlreadyExists_Name" xml:space="preserve">
-    <value>Cannot create '{0}' because a file or directory with the same name already exists.</value>
-  </data>
 </root>
index 7137155589b23393e97fe0603eb448f7749e41f5..3bc59997f7f0c4c413d29eab9bfa54bdf3550682 100644 (file)
@@ -2,7 +2,7 @@
   <PropertyGroup>
     <IsPartialFacadeAssembly>true</IsPartialFacadeAssembly>
     <Nullable>enable</Nullable>
-    <TargetFrameworks>$(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-Unix;$(NetCoreAppCurrent)-Browser</TargetFrameworks>
+    <TargetFrameworks>$(NetCoreAppCurrent)</TargetFrameworks>
   </PropertyGroup>
   <ItemGroup>
     <Compile Include="System\Runtime\CompilerServices\IDispatchConstantAttribute.cs" />
@@ -33,9 +33,6 @@
     <Compile Include="System\Runtime\InteropServices\ImportedFromTypeLibAttribute.cs" />
     <Compile Include="System\Runtime\InteropServices\ManagedToNativeComInteropStubAttribute.cs" />
     <Compile Include="System\Runtime\InteropServices\PrimaryInteropAssemblyAttribute.cs" />
-    <Compile Include="System\Runtime\InteropServices\PosixSignal.cs" />
-    <Compile Include="System\Runtime\InteropServices\PosixSignalContext.cs" />
-    <Compile Include="System\Runtime\InteropServices\PosixSignalRegistration.cs" />
     <Compile Include="System\Runtime\InteropServices\RegistrationClassContext.cs" />
     <Compile Include="System\Runtime\InteropServices\RegistrationConnectionType.cs" />
     <Compile Include="System\Runtime\InteropServices\RuntimeEnvironment.cs" />
     <Compile Include="System\Security\SecureStringMarshal.cs" />
     <Compile Include="$(CommonPath)System\Obsoletions.cs" Link="Common\System\Obsoletions.cs" />
   </ItemGroup>
-  <ItemGroup Condition="'$(TargetsUnix)' == 'true'">
-    <Compile Include="System\Runtime\InteropServices\PosixSignalRegistration.Unix.cs" />
-    <Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.PosixSignal.cs" Link="Common\Interop\Unix\Interop.PosixSignal.cs" />
-    <Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.InitializeTerminalAndSignalHandling.cs" Link="Common\Interop\Unix\Interop.InitializeTerminalAndSignalHandling.cs" />
-    <Compile Include="$(CommonPath)Interop\Unix\Interop.Libraries.cs" Link="Common\Interop\Unix\Interop.Libraries.cs" />
-    <Compile Include="$(CommonPath)Interop\Unix\Interop.Errors.cs" Link="Common\CoreLib\Interop\Unix\Interop.Errors.cs" />
-    <Compile Include="$(CommonPath)Interop\Unix\Interop.IOErrors.cs" Link="Common\Interop\Unix\Interop.IOErrors.cs" />
-  </ItemGroup>
-  <ItemGroup Condition="'$(TargetsWindows)' == 'true'">
-    <Compile Include="System\Runtime\InteropServices\PosixSignalRegistration.Windows.cs" />
-    <Compile Include="$(CommonPath)System\IO\Win32Marshal.cs" Link="Common\System\IO\Win32Marshal.cs" />
-    <Compile Include="$(CommonPath)Interop\Windows\Interop.BOOL.cs" Link="Common\Interop\Windows\Interop.BOOL.cs" />
-    <Compile Include="$(CommonPath)Interop\Windows\Interop.Errors.cs" Link="Common\Interop\Windows\Interop.Errors.cs" />
-    <Compile Include="$(CommonPath)Interop\Windows\Interop.Libraries.cs" Link="Common\Interop\Windows\Interop.Libraries.cs" />
-    <Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.FormatMessage.cs" Link="Common\Interop\Windows\Interop.FormatMessage.cs" />
-    <Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.SetConsoleCtrlHandler.cs" Link="Common\Interop\Windows\Interop.SetConsoleCtrlHandler.cs" />
-  </ItemGroup>
-  <ItemGroup Condition="'$(TargetsBrowser)' == 'true'">
-    <Compile Include="System\Runtime\InteropServices\PosixSignalRegistration.Unsupported.cs" />
-  </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="$(CoreLibProject)" />
   </ItemGroup>
-</Project>
\ No newline at end of file
+</Project>
diff --git a/src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/PosixSignal.cs b/src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/PosixSignal.cs
deleted file mode 100644 (file)
index e1f278f..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Runtime.Versioning;
-
-namespace System.Runtime.InteropServices
-{
-    /// <summary>Specifies a POSIX signal number.</summary>
-    public enum PosixSignal
-    {
-        /// <summary>Hangup</summary>
-        SIGHUP = -1,
-
-        /// <summary>Interrupt</summary>
-        SIGINT = -2,
-
-        /// <summary>Quit</summary>
-        SIGQUIT = -3,
-
-        /// <summary>Termination</summary>
-        SIGTERM = -4,
-
-        /// <summary>Child stopped</summary>
-        [UnsupportedOSPlatform("windows")]
-        SIGCHLD = -5,
-
-        /// <summary>Continue if stopped</summary>
-        [UnsupportedOSPlatform("windows")]
-        SIGCONT = -6,
-
-        /// <summary>Window resized</summary>
-        [UnsupportedOSPlatform("windows")]
-        SIGWINCH = -7,
-
-        /// <summary>Terminal input for background process</summary>
-        [UnsupportedOSPlatform("windows")]
-        SIGTTIN = -8,
-
-        /// <summary>Terminal output for background process</summary>
-        [UnsupportedOSPlatform("windows")]
-        SIGTTOU = -9,
-
-        /// <summary>Stop typed at terminal</summary>
-        [UnsupportedOSPlatform("windows")]
-        SIGTSTP = -10
-    }
-}
diff --git a/src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/PosixSignalContext.cs b/src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/PosixSignalContext.cs
deleted file mode 100644 (file)
index cf73dd6..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-namespace System.Runtime.InteropServices
-{
-    /// <summary>
-    /// Provides data for a <see cref="PosixSignalRegistration"/> event.
-    /// </summary>
-    public sealed class PosixSignalContext
-    {
-        /// <summary>
-        /// Initializes a new instance of the <see cref="PosixSignalContext"/> class.
-        /// </summary>
-        public PosixSignalContext(PosixSignal signal) => Signal = signal;
-
-        /// <summary>
-        /// Gets the signal that occurred.
-        /// </summary>
-        public PosixSignal Signal { get; internal set; }
-
-        /// <summary>
-        /// Gets or sets a value that indicates whether to cancel the default handling of the signal. The default is <see langword="false"/>.
-        /// </summary>
-        public bool Cancel { get; set; }
-    }
-}
diff --git a/src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/PosixSignalRegistration.Unix.cs b/src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/PosixSignalRegistration.Unix.cs
deleted file mode 100644 (file)
index f01b2de..0000000
+++ /dev/null
@@ -1,268 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Collections.Generic;
-using System.Threading;
-
-namespace System.Runtime.InteropServices
-{
-    public sealed partial class PosixSignalRegistration
-    {
-        private static volatile bool s_initialized;
-        private static readonly Dictionary<int, List<WeakReference<PosixSignalRegistration>?>> s_registrations = new();
-
-        private readonly Action<PosixSignalContext> _handler;
-        private readonly PosixSignal _signal;
-        private readonly int _signo;
-        private bool _registered;
-        private readonly object _gate = new object();
-
-        private PosixSignalRegistration(PosixSignal signal, int signo, Action<PosixSignalContext> handler)
-        {
-            _signal = signal;
-            _signo = signo;
-            _handler = handler;
-        }
-
-        public static partial PosixSignalRegistration Create(PosixSignal signal, Action<PosixSignalContext> handler)
-        {
-            if (handler == null)
-            {
-                throw new ArgumentNullException(nameof(handler));
-            }
-
-            int signo = Interop.Sys.GetPlatformSignalNumber(signal);
-            if (signo == 0)
-            {
-                throw new PlatformNotSupportedException();
-            }
-
-            PosixSignalRegistration registration = new PosixSignalRegistration(signal, signo, handler);
-            registration.Register();
-            return registration;
-        }
-
-        private unsafe void Register()
-        {
-            if (!s_initialized)
-            {
-                if (!Interop.Sys.InitializeTerminalAndSignalHandling())
-                {
-                    // We can't use Win32Exception because that causes a cycle with
-                    // Microsoft.Win32.Primitives.
-                    Interop.CheckIo(-1);
-                }
-
-                Interop.Sys.SetPosixSignalHandler(&OnPosixSignal);
-                s_initialized = true;
-            }
-
-            lock (s_registrations)
-            {
-                if (!s_registrations.TryGetValue(_signo, out List<WeakReference<PosixSignalRegistration>?>? signalRegistrations))
-                {
-                    signalRegistrations = new List<WeakReference<PosixSignalRegistration>?>();
-                    s_registrations.Add(_signo, signalRegistrations);
-                }
-
-                if (signalRegistrations.Count == 0)
-                {
-                    if (!Interop.Sys.EnablePosixSignalHandling(_signo))
-                    {
-                        // We can't use Win32Exception because that causes a cycle with
-                        // Microsoft.Win32.Primitives.
-                        Interop.CheckIo(-1);
-                    }
-                }
-
-                signalRegistrations.Add(new WeakReference<PosixSignalRegistration>(this));
-            }
-
-            _registered = true;
-        }
-
-        private bool CallHandler(PosixSignalContext context)
-        {
-            lock (_gate)
-            {
-                if (_registered)
-                {
-                    _handler(context);
-                    return true;
-                }
-
-                return false;
-            }
-        }
-
-        [UnmanagedCallersOnly]
-        private static int OnPosixSignal(int signo, PosixSignal signal)
-        {
-            PosixSignalRegistration?[]? registrations = GetRegistrations(signo);
-            if (registrations != null)
-            {
-                // 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.
-
-                // For terminate/interrupt signals we use a dedicated Thread
-                // in case the ThreadPool is saturated.
-                bool useDedicatedThread = signal == PosixSignal.SIGINT ||
-                                          signal == PosixSignal.SIGQUIT ||
-                                          signal == PosixSignal.SIGTERM;
-
-                if (useDedicatedThread)
-                {
-                    Thread handlerThread = new Thread(HandleSignal)
-                    {
-                        IsBackground = true,
-                        Name = ".NET Signal Handler"
-                    };
-                    handlerThread.UnsafeStart((signo, registrations));
-                }
-                else
-                {
-                    ThreadPool.UnsafeQueueUserWorkItem(HandleSignal, (signo, registrations));
-                }
-
-                return 1;
-            }
-
-            return 0;
-        }
-
-        private static PosixSignalRegistration?[]? GetRegistrations(int signo)
-        {
-            lock (s_registrations)
-            {
-                if (s_registrations.TryGetValue(signo, out List<WeakReference<PosixSignalRegistration>?>? signalRegistrations))
-                {
-                    if (signalRegistrations.Count != 0)
-                    {
-                        var registrations = new PosixSignalRegistration?[signalRegistrations.Count];
-                        bool hasRegistrations = false;
-                        bool pruneWeakReferences = false;
-
-                        for (int i = 0; i < signalRegistrations.Count; i++)
-                        {
-                            if (signalRegistrations[i]!.TryGetTarget(out PosixSignalRegistration? registration))
-                            {
-                                registrations[i] = registration;
-                                hasRegistrations = true;
-                            }
-                            else
-                            {
-                                // WeakReference no longer holds an object. PosixSignalRegistration got finalized.
-                                signalRegistrations[i] = null;
-                                pruneWeakReferences = true;
-                            }
-                        }
-
-                        if (pruneWeakReferences)
-                        {
-                            signalRegistrations.RemoveAll(item => item is null);
-                        }
-
-                        if (hasRegistrations)
-                        {
-                            return registrations;
-                        }
-                        else
-                        {
-                            Interop.Sys.DisablePosixSignalHandling(signo);
-                        }
-                    }
-                }
-                return null;
-            }
-        }
-
-        private static void HandleSignal(object? state)
-        {
-            HandleSignal(((int, PosixSignalRegistration?[]))state!);
-        }
-
-        private static void HandleSignal((int signo, PosixSignalRegistration?[]? registrations) state)
-        {
-            do
-            {
-                bool handlersCalled = false;
-                if (state.registrations != null)
-                {
-                    PosixSignalContext ctx = new(0);
-                    foreach (PosixSignalRegistration? registration in state.registrations)
-                    {
-                        if (registration != null)
-                        {
-                            // Different values for PosixSignal map to the same signo.
-                            // Match the PosixSignal value used when registering.
-                            ctx.Signal = registration._signal;
-                            if (registration.CallHandler(ctx))
-                            {
-                                handlersCalled = true;
-                            }
-                        }
-                    }
-
-                    if (ctx.Cancel)
-                    {
-                        return;
-                    }
-                }
-
-                if (Interop.Sys.HandleNonCanceledPosixSignal(state.signo, handlersCalled ? 0 : 1))
-                {
-                    return;
-                }
-
-                // HandleNonCanceledPosixSignal returns false when handlers got registered.
-                state.registrations = GetRegistrations(state.signo);
-            } while (true);
-        }
-
-        public partial void Dispose()
-        {
-            if (_registered)
-            {
-                lock (s_registrations)
-                {
-                    List<WeakReference<PosixSignalRegistration>?> signalRegistrations = s_registrations[_signo];
-                    bool pruneWeakReferences = false;
-                    for (int i = 0; i < signalRegistrations.Count; i++)
-                    {
-                        if (signalRegistrations[i]!.TryGetTarget(out PosixSignalRegistration? registration))
-                        {
-                            if (ReferenceEquals(this, registration))
-                            {
-                                signalRegistrations.RemoveAt(i);
-                                break;
-                            }
-                        }
-                        else
-                        {
-                            // WeakReference no longer holds an object. PosixSignalRegistration got finalized.
-                            signalRegistrations[i] = null;
-                            pruneWeakReferences = true;
-                        }
-                    }
-
-                    if (pruneWeakReferences)
-                    {
-                        signalRegistrations.RemoveAll(item => item is null);
-                    }
-
-                    if (signalRegistrations.Count == 0)
-                    {
-                        Interop.Sys.DisablePosixSignalHandling(_signo);
-                    }
-                }
-
-                // Synchronize with _handler invocations.
-                lock (_gate)
-                {
-                    _registered = false;
-                }
-            }
-        }
-    }
-}
diff --git a/src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/PosixSignalRegistration.Unsupported.cs b/src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/PosixSignalRegistration.Unsupported.cs
deleted file mode 100644 (file)
index 4bfd2ea..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-namespace System.Runtime.InteropServices
-{
-    public sealed partial class PosixSignalRegistration
-    {
-        private PosixSignalRegistration() { }
-
-        public static partial PosixSignalRegistration Create(PosixSignal signal, Action<PosixSignalContext> handler)
-        {
-            if (handler is null)
-            {
-                throw new ArgumentNullException(nameof(handler));
-            }
-
-            throw new PlatformNotSupportedException();
-        }
-
-        public partial void Dispose() { }
-    }
-}
diff --git a/src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/PosixSignalRegistration.Windows.cs b/src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/PosixSignalRegistration.Windows.cs
deleted file mode 100644 (file)
index d3e5405..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Collections.Generic;
-using System.IO;
-
-namespace System.Runtime.InteropServices
-{
-    public sealed unsafe partial class PosixSignalRegistration
-    {
-        private static readonly HashSet<Token> s_handlers = new();
-
-        private Token? _token;
-
-        private PosixSignalRegistration(Token token) => _token = token;
-
-        private static object SyncObj => s_handlers;
-
-        public static partial PosixSignalRegistration Create(PosixSignal signal, Action<PosixSignalContext> handler)
-        {
-            if (handler is null)
-            {
-                throw new ArgumentNullException(nameof(handler));
-            }
-
-            lock (SyncObj)
-            {
-                switch (signal)
-                {
-                    case PosixSignal.SIGINT:
-                    case PosixSignal.SIGQUIT:
-                    case PosixSignal.SIGTERM:
-                    case PosixSignal.SIGHUP:
-                        break;
-
-                    default:
-                        throw new PlatformNotSupportedException();
-                }
-
-                if (s_handlers.Count == 0 &&
-                    !Interop.Kernel32.SetConsoleCtrlHandler(&HandlerRoutine, Add: true))
-                {
-                    throw Win32Marshal.GetExceptionForLastWin32Error();
-                }
-
-                var token = new Token(signal, handler);
-                s_handlers.Add(token);
-                return new PosixSignalRegistration(token);
-            }
-        }
-
-        public partial void Dispose()
-        {
-            lock (SyncObj)
-            {
-                if (_token is Token token)
-                {
-                    _token = null;
-
-                    s_handlers.Remove(token);
-                    if (s_handlers.Count == 0 &&
-                        !Interop.Kernel32.SetConsoleCtrlHandler(&HandlerRoutine, Add: false))
-                    {
-                        throw Win32Marshal.GetExceptionForLastWin32Error();
-                    }
-                }
-            }
-        }
-
-        [UnmanagedCallersOnly]
-        private static Interop.BOOL HandlerRoutine(int dwCtrlType)
-        {
-            PosixSignal signal;
-            switch (dwCtrlType)
-            {
-                case Interop.Kernel32.CTRL_C_EVENT:
-                    signal = PosixSignal.SIGINT;
-                    break;
-
-                case Interop.Kernel32.CTRL_BREAK_EVENT:
-                    signal = PosixSignal.SIGQUIT;
-                    break;
-
-                case Interop.Kernel32.CTRL_SHUTDOWN_EVENT:
-                    signal = PosixSignal.SIGTERM;
-                    break;
-
-                case Interop.Kernel32.CTRL_CLOSE_EVENT:
-                    signal = PosixSignal.SIGHUP;
-                    break;
-
-                default:
-                    return Interop.BOOL.FALSE;
-            }
-
-            List<Token>? tokens = null;
-            lock (SyncObj)
-            {
-                foreach (Token token in s_handlers)
-                {
-                    if (token.Signal == signal)
-                    {
-                        (tokens ??= new()).Add(token);
-                    }
-                }
-            }
-
-            if (tokens is null)
-            {
-                return Interop.BOOL.FALSE;
-            }
-
-            var context = new PosixSignalContext(signal);
-            foreach (Token handler in tokens)
-            {
-                handler.Handler(context);
-            }
-
-            return context.Cancel ? Interop.BOOL.TRUE : Interop.BOOL.FALSE;
-        }
-
-        private sealed class Token
-        {
-            public Token(PosixSignal signal, Action<PosixSignalContext> handler)
-            {
-                Signal = signal;
-                Handler = handler;
-            }
-
-            public PosixSignal Signal { get; }
-            public Action<PosixSignalContext> Handler { get; }
-        }
-    }
-}
diff --git a/src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/PosixSignalRegistration.cs b/src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/PosixSignalRegistration.cs
deleted file mode 100644 (file)
index fb2c675..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.IO;
-using System.Runtime.Versioning;
-
-namespace System.Runtime.InteropServices
-{
-    /// <summary>Handles a <see cref="PosixSignal"/>.</summary>
-    public sealed partial class PosixSignalRegistration : IDisposable
-    {
-        /// <summary>Registers a <paramref name="handler"/> that is invoked when the <paramref name="signal"/> occurs.</summary>
-        /// <param name="signal">The signal to register for.</param>
-        /// <param name="handler">The handler that gets invoked.</param>
-        /// <returns>A <see cref="PosixSignalRegistration"/> instance that can be disposed to unregister the handler.</returns>
-        /// <exception cref="ArgumentNullException"><paramref name="handler"/> is <see langword="null"/>.</exception>
-        /// <exception cref="PlatformNotSupportedException"><paramref name="signal"/> is not supported by the platform.</exception>
-        /// <exception cref="IOException">An error occurred while setting up the signal handling or while installing the handler for the specified signal.</exception>
-        /// <remarks>
-        /// Raw values can be provided for <paramref name="signal"/> on Unix by casting them to <see cref="PosixSignal"/>.
-        /// Default handling of the signal can be canceled through <see cref="PosixSignalContext.Cancel"/>.
-        /// <see cref="PosixSignal.SIGINT"/> and <see cref="PosixSignal.SIGQUIT"/> can be canceled on both
-        /// Windows and on Unix platforms; <see cref="PosixSignal.SIGTERM"/> can only be canceled on Unix.
-        /// On Unix, terminal configuration can be canceled for <see cref="PosixSignal.SIGCHLD"/> and <see cref="PosixSignal.SIGCONT"/>.
-        /// </remarks>
-        [UnsupportedOSPlatform("android")]
-        [UnsupportedOSPlatform("browser")]
-        [UnsupportedOSPlatform("ios")]
-        [UnsupportedOSPlatform("maccatalyst")]
-        [UnsupportedOSPlatform("tvos")]
-        public static partial PosixSignalRegistration Create(PosixSignal signal, Action<PosixSignalContext> handler);
-
-        /// <summary>Unregister the handler.</summary>
-        public partial void Dispose();
-
-        ~PosixSignalRegistration() => Dispose();
-    }
-}
index 33204d0ee7cc939f676458856ea9232bc2d84b08..f0ffe70d47c314582a002313a5df44c7d3ac2bac 100644 (file)
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
-    <TargetFrameworks>$(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-Unix;$(NetCoreAppCurrent)-Browser</TargetFrameworks>
+    <TargetFrameworks>$(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-Unix</TargetFrameworks>
     <TestRuntime>true</TestRuntime>
     <IncludeRemoteExecutor>true</IncludeRemoteExecutor>
   </PropertyGroup>
     <Compile Include="System\Runtime\InteropServices\PosixSignalRegistrationTests.Unix.cs" />
     <Compile Include="$(CommonPath)Interop\Unix\Interop.Libraries.cs" Link="Common\Interop\Unix\Interop.Libraries.cs" />
   </ItemGroup>
-  <ItemGroup Condition="'$(TargetsBrowser)' == 'true'">
-    <Compile Include="System\Runtime\InteropServices\PosixSignalRegistrationTests.Browser.cs" />
-  </ItemGroup>
 </Project>
diff --git a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/PosixSignalRegistrationTests.Browser.cs b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/PosixSignalRegistrationTests.Browser.cs
deleted file mode 100644 (file)
index 2202ed2..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Collections.Generic;
-
-namespace System.Tests
-{
-    public partial class PosixSignalRegistrationTests
-    {
-        public static IEnumerable<object[]> UninstallableSignals() => Enumerable.Empty<object[]>();
-
-        public static IEnumerable<object[]> SupportedSignals() => Enumerable.Empty<object[]>();
-
-        public static IEnumerable<object[]> UnsupportedSignals()
-        {
-            foreach (PosixSignal signal in Enum.GetValues<PosixSignal>())
-            {
-                yield return new object[] { signal };
-            }
-
-            yield return new object[] { 0 };
-            yield return new object[] { 3 };
-            yield return new object[] { -1000 };
-            yield return new object[] { 1000 };
-        }
-    }
-}
index 1716a3ba24f7f4b679e32ce756d4d0366de03a79..e08d77565513a126785393ef9010450339c7dc25 100644 (file)
@@ -14,23 +14,37 @@ namespace System.Tests
     {
         public static IEnumerable<object[]> UninstallableSignals()
         {
-            yield return new object[] { (PosixSignal)9 };
+            if (PlatformDetection.IsNotMobile)
+            {
+                yield return new object[] { (PosixSignal)9 };
+            }
         }
 
         public static IEnumerable<object[]> SupportedSignals()
         {
-            foreach (PosixSignal value in Enum.GetValues(typeof(PosixSignal)))
-                yield return new object[] { value };
+            if (PlatformDetection.IsNotMobile)
+            {
+                foreach (PosixSignal value in Enum.GetValues(typeof(PosixSignal)))
+                    yield return new object[] { value };
+            }
         }
 
         public static IEnumerable<object[]> UnsupportedSignals()
         {
+            if (PlatformDetection.IsMobile)
+            {
+                foreach (PosixSignal value in Enum.GetValues(typeof(PosixSignal)))
+                    yield return new object[] { value };
+            }
+
             yield return new object[] { 0 };
             yield return new object[] { -1000 };
             yield return new object[] { 1000 };
         }
 
-        [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
+        public static bool NotMobileAndRemoteExecutable => PlatformDetection.IsNotMobile && RemoteExecutor.IsSupported;
+
+        [ConditionalTheory(nameof(NotMobileAndRemoteExecutable))]
         [MemberData(nameof(SupportedSignals))]
         public void SignalHandlerCalledForKnownSignals(PosixSignal s)
         {
@@ -55,7 +69,7 @@ namespace System.Tests
             }, s.ToString()).Dispose();
         }
 
-        [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
+        [ConditionalTheory(nameof(NotMobileAndRemoteExecutable))]
         [MemberData(nameof(PosixSignalAsRawValues))]
         public void SignalHandlerCalledForRawSignals(PosixSignal s)
         {
@@ -80,7 +94,7 @@ namespace System.Tests
             }, s.ToString()).Dispose();
         }
 
-        [Fact]
+        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMobile))]
         public void SignalHandlerWorksForSecondRegistration()
         {
             PosixSignal signal = PosixSignal.SIGCONT;
@@ -104,7 +118,7 @@ namespace System.Tests
             }
         }
 
-        [Fact]
+        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMobile))]
         public void SignalHandlerNotCalledWhenDisposed()
         {
             PosixSignal signal = PosixSignal.SIGCONT;
@@ -118,7 +132,7 @@ namespace System.Tests
             Thread.Sleep(100);
         }
 
-        [Fact]
+        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMobile))]
         public void SignalHandlerNotCalledWhenFinalized()
         {
             PosixSignal signal = PosixSignal.SIGCONT;
@@ -140,7 +154,7 @@ namespace System.Tests
             }
         }
 
-        [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
+        [ConditionalTheory(nameof(NotMobileAndRemoteExecutable))]
         [InlineData(PosixSignal.SIGINT, true, 0)]
         [InlineData(PosixSignal.SIGINT, false, 130)]
         [InlineData(PosixSignal.SIGTERM, true, 0)]