Skip to content

Commit f1bf5ee

Browse files
authored
Add Windows support to PosixSignal (#55333)
* Add Windows support to PosixSignal * Address PR feedback
1 parent 5af27a5 commit f1bf5ee

26 files changed

+502
-287
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using Microsoft.Win32.SafeHandles;
5+
using System;
6+
using System.Runtime.InteropServices;
7+
8+
internal static partial class Interop
9+
{
10+
internal static partial class Kernel32
11+
{
12+
internal delegate bool ConsoleCtrlHandlerRoutine(int controlType);
13+
14+
[DllImport(Libraries.Kernel32, SetLastError = true)]
15+
internal static extern bool SetConsoleCtrlHandler(ConsoleCtrlHandlerRoutine handler, bool addOrRemove);
16+
}
17+
}
Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4-
using Microsoft.Win32.SafeHandles;
5-
using System;
64
using System.Runtime.InteropServices;
75

86
internal static partial class Interop
@@ -11,10 +9,11 @@ internal static partial class Kernel32
119
{
1210
internal const int CTRL_C_EVENT = 0;
1311
internal const int CTRL_BREAK_EVENT = 1;
14-
15-
internal delegate bool ConsoleCtrlHandlerRoutine(int controlType);
12+
internal const int CTRL_CLOSE_EVENT = 2;
13+
internal const int CTRL_LOGOFF_EVENT = 5;
14+
internal const int CTRL_SHUTDOWN_EVENT = 6;
1615

1716
[DllImport(Libraries.Kernel32, SetLastError = true)]
18-
internal static extern bool SetConsoleCtrlHandler(ConsoleCtrlHandlerRoutine handler, bool addOrRemove);
17+
internal static extern unsafe bool SetConsoleCtrlHandler(delegate* unmanaged<int, BOOL> HandlerRoutine, bool Add);
1918
}
2019
}

src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@
8282
Link="Common\Interop\Windows\Kernel32\Interop.LoadLibrary.cs" />
8383
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.FreeLibrary.cs"
8484
Link="Common\Interop\Windows\Kernel32\Interop.FreeLibrary.cs" />
85-
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.SetConsoleCtrlHandler.cs"
86-
Link="Common\Interop\Windows\Kernel32\Interop.SetConsoleCtrlHandler.cs" />
85+
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.SetConsoleCtrlHandler.Delegate.cs"
86+
Link="Common\Interop\Windows\Kernel32\Interop.SetConsoleCtrlHandler.Delegate.cs" />
8787
<Compile Include="$(CommonPath)Interop\Windows\WtsApi32\Interop.Constants.cs"
8888
Link="Common\Interop\Windows\WtsApi32\Interop.Constants.cs" />
8989
<Compile Include="$(CommonPath)Interop\Windows\WtsApi32\Interop.WTSRegisterSessionNotification.cs"

src/libraries/System.Console/src/System.Console.csproj

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,6 @@
119119
Link="Common\Interop\Windows\Interop.ReadConsoleOutput.cs" />
120120
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.SetConsoleCP.cs"
121121
Link="Common\Interop\Windows\Interop.SetConsoleCP.cs" />
122-
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.SetConsoleCtrlHandler.cs"
123-
Link="Common\Interop\Windows\Interop.SetConsoleCtrlHandler.cs" />
124122
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.SetConsoleCursorPosition.cs"
125123
Link="Common\Interop\Windows\Interop.SetConsoleCursorPosition.cs" />
126124
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.SetConsoleOutputCP.cs"

src/libraries/System.Console/src/System/Console.cs

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Diagnostics;
55
using System.IO;
66
using System.Runtime.CompilerServices;
7+
using System.Runtime.InteropServices;
78
using System.Runtime.Versioning;
89
using System.Text;
910
using System.Threading;
@@ -31,7 +32,8 @@ public static class Console
3132
private static bool s_isErrorTextWriterRedirected;
3233

3334
private static ConsoleCancelEventHandler? s_cancelCallbacks;
34-
private static ConsolePal.ControlCHandlerRegistrar? s_registrar;
35+
private static PosixSignalRegistration? s_sigIntRegistration;
36+
private static PosixSignalRegistration? s_sigQuitRegistration;
3537

3638
[UnsupportedOSPlatform("android")]
3739
[UnsupportedOSPlatform("browser")]
@@ -589,11 +591,14 @@ public static event ConsoleCancelEventHandler? CancelKeyPress
589591
{
590592
s_cancelCallbacks += value;
591593

592-
// If we haven't registered our control-C handler, do it.
593-
if (s_registrar == null)
594+
// If we haven't registered our control-C/Break handlers, do it.
595+
if (s_sigIntRegistration is null)
594596
{
595-
s_registrar = new ConsolePal.ControlCHandlerRegistrar();
596-
s_registrar.Register();
597+
Debug.Assert(s_sigQuitRegistration is null);
598+
599+
Action<PosixSignalContext> handler = HandlePosixSignal;
600+
s_sigIntRegistration = PosixSignalRegistration.Create(PosixSignal.SIGINT, handler);
601+
s_sigQuitRegistration = PosixSignalRegistration.Create(PosixSignal.SIGQUIT, handler);
597602
}
598603
}
599604
}
@@ -602,10 +607,13 @@ public static event ConsoleCancelEventHandler? CancelKeyPress
602607
lock (s_syncObject)
603608
{
604609
s_cancelCallbacks -= value;
605-
if (s_registrar != null && s_cancelCallbacks == null)
610+
611+
// If there are no more callbacks, unregister registered posix signal handlers.
612+
if (s_cancelCallbacks == null)
606613
{
607-
s_registrar.Unregister();
608-
s_registrar = null;
614+
s_sigIntRegistration?.Dispose();
615+
s_sigQuitRegistration?.Dispose();
616+
s_sigIntRegistration = s_sigQuitRegistration = null;
609617
}
610618
}
611619
}
@@ -960,18 +968,17 @@ public static void Write(string? value)
960968
Out.Write(value);
961969
}
962970

963-
internal static bool HandleBreakEvent(ConsoleSpecialKey controlKey, bool cancel = false)
971+
private static void HandlePosixSignal(PosixSignalContext ctx)
964972
{
965-
ConsoleCancelEventHandler? handler = s_cancelCallbacks;
966-
if (handler == null)
973+
Debug.Assert(ctx.Signal == PosixSignal.SIGINT || ctx.Signal == PosixSignal.SIGQUIT);
974+
975+
if (s_cancelCallbacks is ConsoleCancelEventHandler handler)
967976
{
968-
return false;
977+
var args = new ConsoleCancelEventArgs(ctx.Signal == PosixSignal.SIGINT ? ConsoleSpecialKey.ControlC : ConsoleSpecialKey.ControlBreak);
978+
args.Cancel = ctx.Cancel;
979+
handler(null, args);
980+
ctx.Cancel = args.Cancel;
969981
}
970-
971-
var args = new ConsoleCancelEventArgs(controlKey);
972-
args.Cancel = cancel;
973-
handler(null, args);
974-
return args.Cancel;
975982
}
976983
}
977984
}

src/libraries/System.Console/src/System/ConsolePal.Android.cs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -152,14 +152,5 @@ public static int WindowHeight
152152
public static void SetWindowPosition(int left, int top) => throw new PlatformNotSupportedException();
153153

154154
public static void SetWindowSize(int width, int height) => throw new PlatformNotSupportedException();
155-
156-
internal sealed class ControlCHandlerRegistrar
157-
{
158-
internal ControlCHandlerRegistrar() => throw new PlatformNotSupportedException();
159-
160-
internal void Register() => throw new PlatformNotSupportedException();
161-
162-
internal void Unregister() => throw new PlatformNotSupportedException();
163-
}
164155
}
165156
}

src/libraries/System.Console/src/System/ConsolePal.Unix.cs

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1442,37 +1442,6 @@ public override void Flush()
14421442
}
14431443
}
14441444

1445-
internal sealed class ControlCHandlerRegistrar
1446-
{
1447-
private PosixSignalRegistration? _sigIntRegistration;
1448-
private PosixSignalRegistration? _sigQuitRegistration;
1449-
1450-
internal unsafe void Register()
1451-
{
1452-
Debug.Assert(_sigIntRegistration is null);
1453-
1454-
_sigIntRegistration = PosixSignalRegistration.Create(PosixSignal.SIGINT, HandlePosixSignal);
1455-
_sigQuitRegistration = PosixSignalRegistration.Create(PosixSignal.SIGQUIT, HandlePosixSignal);
1456-
}
1457-
1458-
internal void Unregister()
1459-
{
1460-
Debug.Assert(_sigIntRegistration is not null);
1461-
1462-
_sigIntRegistration?.Dispose();
1463-
_sigQuitRegistration?.Dispose();
1464-
}
1465-
1466-
private static void HandlePosixSignal(PosixSignalContext ctx)
1467-
{
1468-
Debug.Assert(ctx.Signal == PosixSignal.SIGINT || ctx.Signal == PosixSignal.SIGQUIT);
1469-
1470-
ConsoleSpecialKey controlKey = ctx.Signal == PosixSignal.SIGINT ? ConsoleSpecialKey.ControlC : ConsoleSpecialKey.ControlBreak;
1471-
bool cancel = Console.HandleBreakEvent(controlKey, ctx.Cancel);
1472-
ctx.Cancel = cancel;
1473-
}
1474-
}
1475-
14761445
private sealed class ReadOnlyMemoryContentComparer : IEqualityComparer<ReadOnlyMemory<char>>
14771446
{
14781447
public bool Equals(ReadOnlyMemory<char> x, ReadOnlyMemory<char> y) =>

src/libraries/System.Console/src/System/ConsolePal.WebAssembly.cs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -224,14 +224,5 @@ public static int WindowHeight
224224
public static void SetWindowPosition(int left, int top) => throw new PlatformNotSupportedException();
225225

226226
public static void SetWindowSize(int width, int height) => throw new PlatformNotSupportedException();
227-
228-
internal sealed class ControlCHandlerRegistrar
229-
{
230-
internal ControlCHandlerRegistrar() => throw new PlatformNotSupportedException();
231-
232-
internal void Register() => throw new PlatformNotSupportedException();
233-
234-
internal void Unregister() => throw new PlatformNotSupportedException();
235-
}
236227
}
237228
}

src/libraries/System.Console/src/System/ConsolePal.Windows.cs

Lines changed: 0 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1224,52 +1224,5 @@ private static unsafe int WriteFileNative(IntPtr hFile, ReadOnlySpan<byte> bytes
12241224
return errorCode;
12251225
}
12261226
}
1227-
1228-
internal sealed class ControlCHandlerRegistrar
1229-
{
1230-
private bool _handlerRegistered;
1231-
private readonly Interop.Kernel32.ConsoleCtrlHandlerRoutine _handler;
1232-
1233-
internal ControlCHandlerRegistrar()
1234-
{
1235-
_handler = new Interop.Kernel32.ConsoleCtrlHandlerRoutine(BreakEvent);
1236-
}
1237-
1238-
internal void Register()
1239-
{
1240-
Debug.Assert(!_handlerRegistered);
1241-
1242-
bool r = Interop.Kernel32.SetConsoleCtrlHandler(_handler, true);
1243-
if (!r)
1244-
{
1245-
throw Win32Marshal.GetExceptionForLastWin32Error();
1246-
}
1247-
1248-
_handlerRegistered = true;
1249-
}
1250-
1251-
internal void Unregister()
1252-
{
1253-
Debug.Assert(_handlerRegistered);
1254-
1255-
bool r = Interop.Kernel32.SetConsoleCtrlHandler(_handler, false);
1256-
if (!r)
1257-
{
1258-
throw Win32Marshal.GetExceptionForLastWin32Error();
1259-
}
1260-
_handlerRegistered = false;
1261-
}
1262-
1263-
private static bool BreakEvent(int controlType)
1264-
{
1265-
if (controlType != Interop.Kernel32.CTRL_C_EVENT &&
1266-
controlType != Interop.Kernel32.CTRL_BREAK_EVENT)
1267-
{
1268-
return false;
1269-
}
1270-
1271-
return Console.HandleBreakEvent(controlType == Interop.Kernel32.CTRL_C_EVENT ? ConsoleSpecialKey.ControlC : ConsoleSpecialKey.ControlBreak);
1272-
}
1273-
}
12741227
}
12751228
}

src/libraries/System.Console/src/System/ConsolePal.iOS.cs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -155,14 +155,5 @@ public static int WindowHeight
155155
public static void SetWindowPosition(int left, int top) => throw new PlatformNotSupportedException();
156156

157157
public static void SetWindowSize(int width, int height) => throw new PlatformNotSupportedException();
158-
159-
internal sealed class ControlCHandlerRegistrar
160-
{
161-
internal ControlCHandlerRegistrar() => throw new PlatformNotSupportedException();
162-
163-
internal void Register() => throw new PlatformNotSupportedException();
164-
165-
internal void Unregister() => throw new PlatformNotSupportedException();
166-
}
167158
}
168159
}

0 commit comments

Comments
 (0)