Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit ce06190

Browse files
committed
Implement Console.CancelKeyPress on Unix
Implements the currently stubbed out ControlCHandlerRegistrar in terms of libcoreclr's SetConsoleCtrlHandler, so as to play nicely with any other handlers registered by the runtime / debugger and with signal handling in general.
1 parent 41b90e6 commit ce06190

File tree

3 files changed

+50
-5
lines changed

3 files changed

+50
-5
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using Microsoft.Win32.SafeHandles;
5+
using System;
6+
using System.Runtime.InteropServices;
7+
8+
internal partial class Interop
9+
{
10+
internal partial class libcoreclr
11+
{
12+
internal const int CTRL_C_EVENT = 0;
13+
internal const int CTRL_BREAK_EVENT = 1;
14+
15+
internal const int ERROR_NOT_ENOUGH_MEMORY = 0x8;
16+
internal const int ERROR_INVALID_PARAMETER = 0x57;
17+
18+
internal delegate bool ConsoleCtrlHandlerRoutine(int controlType);
19+
20+
[DllImport(Libraries.LibCoreClr, SetLastError = true)]
21+
internal static extern bool SetConsoleCtrlHandler(ConsoleCtrlHandlerRoutine handler, bool addOrRemove);
22+
}
23+
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@
136136
<Compile Include="$(CommonPath)\Interop\Unix\libcoreclr\Interop.GetFileInformation.cs">
137137
<Link>Common\Interop\Unix\Interop.GetFileInformation.cs"</Link>
138138
</Compile>
139+
<Compile Include="$(CommonPath)\Interop\Unix\libcoreclr\Interop.SetConsoleCtrlHandler.cs">
140+
<Link>Common\Interop\Unix\Interop.SetConsoleCtrlHandler.cs"</Link>
141+
</Compile>
139142
</ItemGroup>
140143
<ItemGroup Condition=" '$(TargetsLinux)' == 'true' ">
141144
<Compile Include="$(CommonPath)\Interop\Linux\Interop.Errors.cs">

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

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1173,15 +1173,34 @@ public void Clear()
11731173

11741174
internal sealed class ControlCHandlerRegistrar
11751175
{
1176-
internal void Register()
1176+
private readonly Interop.libcoreclr.ConsoleCtrlHandlerRoutine _handler;
1177+
private bool _handlerRegistered;
1178+
1179+
internal ControlCHandlerRegistrar()
11771180
{
1178-
// UNIXTODO: Install SIGINT signal handler.
1181+
_handler = new Interop.libcoreclr.ConsoleCtrlHandlerRoutine(c =>
1182+
(c == Interop.libcoreclr.CTRL_C_EVENT || c == Interop.libcoreclr.CTRL_BREAK_EVENT) &&
1183+
Console.HandleBreakEvent(c == Interop.libcoreclr.CTRL_C_EVENT ? ConsoleSpecialKey.ControlC : ConsoleSpecialKey.ControlBreak));
11791184
}
11801185

1181-
internal void Unregister()
1186+
internal void Register() { RegisterOrUnregister(true); }
1187+
1188+
internal void Unregister() { RegisterOrUnregister(false); }
1189+
1190+
private void RegisterOrUnregister(bool register)
11821191
{
1183-
// UNIXTODO: remove handler.
1192+
Debug.Assert(register == !_handlerRegistered);
1193+
if (!Interop.libcoreclr.SetConsoleCtrlHandler(_handler, register))
1194+
{
1195+
int error = Marshal.GetLastWin32Error(); // Win32 error code from coreclr PAL, not a Unix errno value
1196+
throw Interop.GetExceptionForIoErrno(
1197+
error == Interop.libcoreclr.ERROR_INVALID_PARAMETER ? Interop.Errors.EINVAL :
1198+
error == Interop.libcoreclr.ERROR_NOT_ENOUGH_MEMORY ? Interop.Errors.ENOMEM :
1199+
Interop.Errors.EIO);
1200+
}
1201+
_handlerRegistered = register;
11841202
}
11851203
}
1204+
11861205
}
1187-
}
1206+
}

0 commit comments

Comments
 (0)