Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Windows support to PosixSignal #55333

Merged
merged 2 commits into from
Jul 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;

internal static partial class Interop
{
internal static partial class Kernel32
{
internal delegate bool ConsoleCtrlHandlerRoutine(int controlType);

[DllImport(Libraries.Kernel32, SetLastError = true)]
internal static extern bool SetConsoleCtrlHandler(ConsoleCtrlHandlerRoutine handler, bool addOrRemove);
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;

internal static partial class Interop
Expand All @@ -11,10 +9,11 @@ internal static partial class Kernel32
{
internal const int CTRL_C_EVENT = 0;
internal const int CTRL_BREAK_EVENT = 1;

internal delegate bool ConsoleCtrlHandlerRoutine(int controlType);
internal const int CTRL_CLOSE_EVENT = 2;
internal const int CTRL_LOGOFF_EVENT = 5;
internal const int CTRL_SHUTDOWN_EVENT = 6;

[DllImport(Libraries.Kernel32, SetLastError = true)]
internal static extern bool SetConsoleCtrlHandler(ConsoleCtrlHandlerRoutine handler, bool addOrRemove);
internal static extern unsafe bool SetConsoleCtrlHandler(delegate* unmanaged<int, BOOL> HandlerRoutine, bool Add);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@
Link="Common\Interop\Windows\Kernel32\Interop.LoadLibrary.cs" />
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.FreeLibrary.cs"
Link="Common\Interop\Windows\Kernel32\Interop.FreeLibrary.cs" />
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.SetConsoleCtrlHandler.cs"
Link="Common\Interop\Windows\Kernel32\Interop.SetConsoleCtrlHandler.cs" />
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.SetConsoleCtrlHandler.Delegate.cs"
Link="Common\Interop\Windows\Kernel32\Interop.SetConsoleCtrlHandler.Delegate.cs" />
<Compile Include="$(CommonPath)Interop\Windows\WtsApi32\Interop.Constants.cs"
Link="Common\Interop\Windows\WtsApi32\Interop.Constants.cs" />
<Compile Include="$(CommonPath)Interop\Windows\WtsApi32\Interop.WTSRegisterSessionNotification.cs"
Expand Down
2 changes: 0 additions & 2 deletions src/libraries/System.Console/src/System.Console.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,6 @@
Link="Common\Interop\Windows\Interop.ReadConsoleOutput.cs" />
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.SetConsoleCP.cs"
Link="Common\Interop\Windows\Interop.SetConsoleCP.cs" />
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.SetConsoleCtrlHandler.cs"
Link="Common\Interop\Windows\Interop.SetConsoleCtrlHandler.cs" />
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.SetConsoleCursorPosition.cs"
Link="Common\Interop\Windows\Interop.SetConsoleCursorPosition.cs" />
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.SetConsoleOutputCP.cs"
Expand Down
41 changes: 24 additions & 17 deletions src/libraries/System.Console/src/System/Console.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
Expand Down Expand Up @@ -31,7 +32,8 @@ public static class Console
private static bool s_isErrorTextWriterRedirected;

private static ConsoleCancelEventHandler? s_cancelCallbacks;
private static ConsolePal.ControlCHandlerRegistrar? s_registrar;
private static PosixSignalRegistration? s_sigIntRegistration;
private static PosixSignalRegistration? s_sigQuitRegistration;

[UnsupportedOSPlatform("android")]
[UnsupportedOSPlatform("browser")]
Expand Down Expand Up @@ -589,11 +591,14 @@ public static event ConsoleCancelEventHandler? CancelKeyPress
{
s_cancelCallbacks += value;

// If we haven't registered our control-C handler, do it.
if (s_registrar == null)
// If we haven't registered our control-C/Break handlers, do it.
if (s_sigIntRegistration is null)
{
s_registrar = new ConsolePal.ControlCHandlerRegistrar();
s_registrar.Register();
Debug.Assert(s_sigQuitRegistration is null);

Action<PosixSignalContext> handler = HandlePosixSignal;
s_sigIntRegistration = PosixSignalRegistration.Create(PosixSignal.SIGINT, handler);
s_sigQuitRegistration = PosixSignalRegistration.Create(PosixSignal.SIGQUIT, handler);
}
}
}
Expand All @@ -602,10 +607,13 @@ public static event ConsoleCancelEventHandler? CancelKeyPress
lock (s_syncObject)
{
s_cancelCallbacks -= value;
if (s_registrar != null && s_cancelCallbacks == null)

// If there are no more callbacks, unregister registered posix signal handlers.
if (s_cancelCallbacks == null)
{
s_registrar.Unregister();
s_registrar = null;
s_sigIntRegistration?.Dispose();
s_sigQuitRegistration?.Dispose();
s_sigIntRegistration = s_sigQuitRegistration = null;
}
}
}
Expand Down Expand Up @@ -960,18 +968,17 @@ public static void Write(string? value)
Out.Write(value);
}

internal static bool HandleBreakEvent(ConsoleSpecialKey controlKey, bool cancel = false)
private static void HandlePosixSignal(PosixSignalContext ctx)
{
ConsoleCancelEventHandler? handler = s_cancelCallbacks;
if (handler == null)
Debug.Assert(ctx.Signal == PosixSignal.SIGINT || ctx.Signal == PosixSignal.SIGQUIT);

if (s_cancelCallbacks is ConsoleCancelEventHandler handler)
{
return false;
var args = new ConsoleCancelEventArgs(ctx.Signal == PosixSignal.SIGINT ? ConsoleSpecialKey.ControlC : ConsoleSpecialKey.ControlBreak);
args.Cancel = ctx.Cancel;
handler(null, args);
stephentoub marked this conversation as resolved.
Show resolved Hide resolved
ctx.Cancel = args.Cancel;
}

var args = new ConsoleCancelEventArgs(controlKey);
args.Cancel = cancel;
handler(null, args);
return args.Cancel;
}
}
}
9 changes: 0 additions & 9 deletions src/libraries/System.Console/src/System/ConsolePal.Android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,14 +152,5 @@ public static int WindowHeight
public static void SetWindowPosition(int left, int top) => throw new PlatformNotSupportedException();

public static void SetWindowSize(int width, int height) => throw new PlatformNotSupportedException();

internal sealed class ControlCHandlerRegistrar
{
internal ControlCHandlerRegistrar() => throw new PlatformNotSupportedException();

internal void Register() => throw new PlatformNotSupportedException();

internal void Unregister() => throw new PlatformNotSupportedException();
}
}
}
31 changes: 0 additions & 31 deletions src/libraries/System.Console/src/System/ConsolePal.Unix.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1442,37 +1442,6 @@ public override void Flush()
}
}

internal sealed class ControlCHandlerRegistrar
{
private PosixSignalRegistration? _sigIntRegistration;
private PosixSignalRegistration? _sigQuitRegistration;

internal unsafe void Register()
{
Debug.Assert(_sigIntRegistration is null);

_sigIntRegistration = PosixSignalRegistration.Create(PosixSignal.SIGINT, HandlePosixSignal);
_sigQuitRegistration = PosixSignalRegistration.Create(PosixSignal.SIGQUIT, HandlePosixSignal);
}

internal void Unregister()
{
Debug.Assert(_sigIntRegistration is not null);

_sigIntRegistration?.Dispose();
_sigQuitRegistration?.Dispose();
}

private static void HandlePosixSignal(PosixSignalContext ctx)
{
Debug.Assert(ctx.Signal == PosixSignal.SIGINT || ctx.Signal == PosixSignal.SIGQUIT);

ConsoleSpecialKey controlKey = ctx.Signal == PosixSignal.SIGINT ? ConsoleSpecialKey.ControlC : ConsoleSpecialKey.ControlBreak;
bool cancel = Console.HandleBreakEvent(controlKey, ctx.Cancel);
ctx.Cancel = cancel;
}
}

private sealed class ReadOnlyMemoryContentComparer : IEqualityComparer<ReadOnlyMemory<char>>
{
public bool Equals(ReadOnlyMemory<char> x, ReadOnlyMemory<char> y) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,14 +224,5 @@ public static int WindowHeight
public static void SetWindowPosition(int left, int top) => throw new PlatformNotSupportedException();

public static void SetWindowSize(int width, int height) => throw new PlatformNotSupportedException();

internal sealed class ControlCHandlerRegistrar
{
internal ControlCHandlerRegistrar() => throw new PlatformNotSupportedException();

internal void Register() => throw new PlatformNotSupportedException();

internal void Unregister() => throw new PlatformNotSupportedException();
}
}
}
47 changes: 0 additions & 47 deletions src/libraries/System.Console/src/System/ConsolePal.Windows.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1224,52 +1224,5 @@ private static unsafe int WriteFileNative(IntPtr hFile, ReadOnlySpan<byte> bytes
return errorCode;
}
}

internal sealed class ControlCHandlerRegistrar
{
private bool _handlerRegistered;
private readonly Interop.Kernel32.ConsoleCtrlHandlerRoutine _handler;

internal ControlCHandlerRegistrar()
{
_handler = new Interop.Kernel32.ConsoleCtrlHandlerRoutine(BreakEvent);
stephentoub marked this conversation as resolved.
Show resolved Hide resolved
}

internal void Register()
{
Debug.Assert(!_handlerRegistered);

bool r = Interop.Kernel32.SetConsoleCtrlHandler(_handler, true);
if (!r)
{
throw Win32Marshal.GetExceptionForLastWin32Error();
}

_handlerRegistered = true;
}

internal void Unregister()
{
Debug.Assert(_handlerRegistered);

bool r = Interop.Kernel32.SetConsoleCtrlHandler(_handler, false);
if (!r)
{
throw Win32Marshal.GetExceptionForLastWin32Error();
}
_handlerRegistered = false;
}

private static bool BreakEvent(int controlType)
{
if (controlType != Interop.Kernel32.CTRL_C_EVENT &&
controlType != Interop.Kernel32.CTRL_BREAK_EVENT)
{
return false;
}

return Console.HandleBreakEvent(controlType == Interop.Kernel32.CTRL_C_EVENT ? ConsoleSpecialKey.ControlC : ConsoleSpecialKey.ControlBreak);
}
}
}
}
9 changes: 0 additions & 9 deletions src/libraries/System.Console/src/System/ConsolePal.iOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,14 +155,5 @@ public static int WindowHeight
public static void SetWindowPosition(int left, int top) => throw new PlatformNotSupportedException();

public static void SetWindowSize(int width, int height) => throw new PlatformNotSupportedException();

internal sealed class ControlCHandlerRegistrar
{
internal ControlCHandlerRegistrar() => throw new PlatformNotSupportedException();

internal void Register() => throw new PlatformNotSupportedException();

internal void Unregister() => throw new PlatformNotSupportedException();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -798,11 +798,17 @@ public OptionalAttribute() { }
}
public enum PosixSignal
{
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("windows")]
stephentoub marked this conversation as resolved.
Show resolved Hide resolved
SIGTSTP = -10,
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("windows")]
SIGTTOU = -9,
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("windows")]
SIGTTIN = -8,
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("windows")]
SIGWINCH = -7,
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("windows")]
SIGCONT = -6,
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("windows")]
SIGCHLD = -5,
SIGTERM = -4,
SIGQUIT = -3,
Expand All @@ -818,6 +824,11 @@ public PosixSignalContext(System.Runtime.InteropServices.PosixSignal signal) { }
public sealed partial class PosixSignalRegistration : System.IDisposable
{
internal PosixSignalRegistration() { }
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("android")]
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("ios")]
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("maccatalyst")]
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("tvos")]
public static System.Runtime.InteropServices.PosixSignalRegistration Create(System.Runtime.InteropServices.PosixSignal signal, System.Action<System.Runtime.InteropServices.PosixSignalContext> handler) { throw null; }
public void Dispose() { }
~PosixSignalRegistration() { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,7 @@
<data name="ArgumentOutOfRange_FileLengthTooBig" xml:space="preserve">
<value>Specified file length was too large for the file system.</value>
</data>
</root>
<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>
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
<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" />
Expand All @@ -52,22 +53,23 @@
</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" />
<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'">
stephentoub marked this conversation as resolved.
Show resolved Hide resolved
<Compile Include="System\Runtime\InteropServices\PosixSignalRegistration.Browser.cs" />
<Compile Include="System\Runtime\InteropServices\PosixSignalRegistration.Unsupported.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(CoreLibProject)" />
Expand Down
Loading