Permalink
Browse files

Separate the Windows portion of the signal module.

This splits out the Windows-specific part of signal and adds a very
simple signal handler that only works with SIGINT and SIGBREAK.
  • Loading branch information...
1 parent 8cfc05a commit f933c70552576ef0cc772f2b3afc120492ae1fbc @jdhardy committed May 20, 2012
@@ -58,9 +58,10 @@
<Compile Include="bz2\dotnetzip\BZip2\Rand.cs" />
<Compile Include="cmath.cs" />
<Compile Include="msvcrt.cs" />
- <Compile Include="NativeSignal.cs" />
<Compile Include="GlobalSuppressions.cs" />
<Compile Include="mmap.cs" />
+ <Compile Include="NtSignalState.cs" />
+ <Compile Include="SimpleSignalState.cs" />
<Compile Include="ResourceMetaPathImporter.cs" />
<Compile Include="signal.cs" />
<Compile Include="winsound.cs" />
@@ -1,34 +0,0 @@
-/* ****************************************************************************
- *
- * Copyright (c) Microsoft Corporation.
- *
- * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
- * copy of the license can be found in the License.html file at the root of this distribution. If
- * you cannot locate the Apache License, Version 2.0, please send an email to
- * ironpy@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
- * by the terms of the Apache License, Version 2.0.
- *
- * You must not remove this notice, or any other, from this software.
- *
- *
- * ***************************************************************************/
-
-using System.Runtime.InteropServices;
-
-namespace IronPython.Modules {
-#if !SILVERLIGHT
- public static class NativeSignal {
-
- //Windows API expects to be given a function pointer like this to handle signals
- internal delegate bool WinSignalsHandler(uint winSignal);
-
- [DllImport("Kernel32")]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static extern bool SetConsoleCtrlHandler(WinSignalsHandler Handler, [MarshalAs(UnmanagedType.Bool)]bool Add);
-
- [DllImport("Kernel32")]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static extern bool GenerateConsoleCtrlEvent(uint dwCtrlEvent, uint dwProcessGroupId);
- }
-#endif
-}
@@ -0,0 +1,129 @@
+/* ****************************************************************************
+ *
+ * Copyright (c) Microsoft Corporation.
+ *
+ * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
+ * copy of the license can be found in the License.html file at the root of this distribution. If
+ * you cannot locate the Apache License, Version 2.0, please send an email to
+ * ironpy@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
+ * by the terms of the Apache License, Version 2.0.
+ *
+ * You must not remove this notice, or any other, from this software.
+ *
+ *
+ * ***************************************************************************/
+
+using System;
+using System.Runtime.InteropServices;
+using IronPython.Runtime;
+
+#if FEATURE_PROCESS
+
+namespace IronPython.Modules {
+ public static partial class PythonSignal {
+ internal class NtSignalState : PythonSignalState {
+ //Windows signals
+ internal const uint CTRL_C_EVENT = 0;
+ internal const uint CTRL_BREAK_EVENT = 1;
+ internal const uint CTRL_CLOSE_EVENT = 2;
+ internal const uint CTRL_LOGOFF_EVENT = 5;
+ internal const uint CTRL_SHUTDOWN_EVENT = 6;
+
+ //We use a single Windows event handler to process all signals. This handler simply
+ //delegates the work out to PySignalToPyHandler.
+ public NativeSignal.WinSignalsHandler WinAllSignalsHandlerDelegate;
+
+ public NtSignalState(PythonContext pc) : base(pc) {
+ WinAllSignalsHandlerDelegate = new NativeSignal.WinSignalsHandler(WindowsEventHandler);
+ NativeSignal.SetConsoleCtrlHandler(this.WinAllSignalsHandlerDelegate, true);
+ }
+
+ //Our implementation of WinSignalsHandler
+ private bool WindowsEventHandler(uint winSignal) {
+ bool retVal;
+ int pySignal;
+
+ switch (winSignal) {
+ case CTRL_C_EVENT:
+ pySignal = SIGINT;
+ break;
+ case CTRL_BREAK_EVENT:
+ pySignal = SIGBREAK;
+ break;
+ case CTRL_CLOSE_EVENT:
+ pySignal = SIGBREAK;
+ break;
+ case CTRL_LOGOFF_EVENT:
+ pySignal = SIGBREAK;
+ break;
+ case CTRL_SHUTDOWN_EVENT:
+ pySignal = SIGBREAK;
+ break;
+ default:
+ throw new Exception("unreachable");
+ }
+
+ lock (PySignalToPyHandler) {
+ if (PySignalToPyHandler[pySignal].GetType() == typeof(int)) {
+ int tempId = (int)PySignalToPyHandler[pySignal];
+
+ if (tempId == SIG_DFL) {
+ //SIG_DFL - we let Windows do whatever it normally would
+ retVal = false;
+ } else if (tempId == SIG_IGN) {
+ //SIG_IGN - we do nothing, but tell Windows we handled the signal
+ retVal = true;
+ } else {
+ throw new Exception("unreachable");
+ }
+ } else if (PySignalToPyHandler[pySignal] == default_int_handler) {
+ if (pySignal != SIGINT) {
+ //We're dealing with the default_int_handlerImpl which we
+ //know doesn't care about the frame parameter
+ retVal = true;
+ default_int_handlerImpl(pySignal, null);
+ } else {
+ //Let the real interrupt handler throw a KeyboardInterrupt for SIGINT.
+ //It handles this far more gracefully than we can
+ retVal = false;
+ }
+ } else {
+ //We're dealing with a callable matching PySignalHandler's signature
+ retVal = true;
+ PySignalHandler temp = (PySignalHandler)Converter.ConvertToDelegate(PySignalToPyHandler[pySignal],
+ typeof(PySignalHandler));
+
+ try {
+ if (SignalPythonContext.PythonOptions.Frames) {
+ temp.Invoke(pySignal, SysModule._getframeImpl(null,
+ 0,
+ SignalPythonContext._mainThreadFunctionStack));
+ } else {
+ temp.Invoke(pySignal, null);
+ }
+ } catch (Exception e) {
+ System.Console.WriteLine(SignalPythonContext.FormatException(e));
+ }
+ }
+ }
+
+ return retVal;
+ }
+ }
+
+ internal static class NativeSignal {
+ // Windows API expects to be given a function pointer like this to handle signals
+ internal delegate bool WinSignalsHandler(uint winSignal);
+
+ [DllImport("Kernel32")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool SetConsoleCtrlHandler(WinSignalsHandler Handler, [MarshalAs(UnmanagedType.Bool)]bool Add);
+
+ [DllImport("Kernel32")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool GenerateConsoleCtrlEvent(uint dwCtrlEvent, uint dwProcessGroupId);
+ }
+ }
+}
+
+#endif
@@ -0,0 +1,85 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using IronPython.Runtime;
+
+#if FEATURE_PROCESS
+
+namespace IronPython.Modules {
+ public static partial class PythonSignal {
+ internal class SimpleSignalState : PythonSignalState {
+ public SimpleSignalState(PythonContext pc)
+ : base(pc) {
+ Console.CancelKeyPress += new ConsoleCancelEventHandler(Console_CancelKeyPress);
+ }
+
+ void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e) {
+ int pySignal;
+ switch(e.SpecialKey) {
+ case ConsoleSpecialKey.ControlC:
+ pySignal = SIGINT;
+ break;
+
+ case ConsoleSpecialKey.ControlBreak:
+ pySignal = SIGBREAK;
+ break;
+
+ default:
+ throw new InvalidOperationException("unreachable");
+ }
+
+ lock (PySignalToPyHandler) {
+ if (PySignalToPyHandler[pySignal].GetType() == typeof(int)) {
+ int tempId = (int)PySignalToPyHandler[pySignal];
+
+ if (tempId == SIG_DFL) {
+ //SIG_DFL - do whatever it normally would
+ return;
+ } else if (tempId == SIG_IGN) {
+ //SIG_IGN - we do nothing, but tell the OS we handled the signal
+ e.Cancel = false;
+ return;
+ } else {
+ throw new Exception("unreachable");
+ }
+ } else if (PySignalToPyHandler[pySignal] == default_int_handler) {
+ if (pySignal != SIGINT) {
+ //We're dealing with the default_int_handlerImpl which we
+ //know doesn't care about the frame parameter
+ e.Cancel = true;
+ default_int_handlerImpl(pySignal, null);
+ return;
+ } else {
+ //Let the real interrupt handler throw a KeyboardInterrupt for SIGINT.
+ //It handles this far more gracefully than we can
+ return;
+ }
+ } else {
+ //We're dealing with a callable matching PySignalHandler's signature
+ PySignalHandler temp = (PySignalHandler)Converter.ConvertToDelegate(PySignalToPyHandler[pySignal],
+ typeof(PySignalHandler));
+
+ try {
+ if (SignalPythonContext.PythonOptions.Frames) {
+ temp.Invoke(pySignal, SysModule._getframeImpl(null,
+ 0,
+ SignalPythonContext._mainThreadFunctionStack));
+ } else {
+ temp.Invoke(pySignal, null);
+ }
+ } catch (Exception ex) {
+ System.Console.WriteLine(SignalPythonContext.FormatException(ex));
+ }
+
+ e.Cancel = true;
+ return;
+ }
+ }
+ }
+ }
+ }
+}
+
+#endif
+
@@ -1428,25 +1428,6 @@ public class stat_result : IList, IList<object> {
[Documentation(@"Send signal sig to the process pid. Constants for the specific signals available on the host platform
are defined in the signal module.")]
public static void kill(CodeContext/*!*/ context, int pid, int sig) {
-
- //The following calls to GenerateConsoleCtrlEvent will fail under
- //most circumstances. We'll try them any ways though as this seems
- //to be the only mechanism in Windows to send signals to processes
- switch (sig) {
- case PythonSignal.SIGINT:
- if (NativeSignal.GenerateConsoleCtrlEvent(PythonSignal.CTRL_C_EVENT, (uint)pid)!= false) {
- return;
- }
- break;
- case PythonSignal.SIGBREAK:
- if (NativeSignal.GenerateConsoleCtrlEvent(PythonSignal.CTRL_BREAK_EVENT, (uint)pid) != false) {
- return;
- }
- break;
- default:
- throw PythonOps.ValueError("signal number out of range");
- }
-
//If the calls to GenerateConsoleCtrlEvent didn't work, simply
//forcefully kill the process.
Process toKill = Process.GetProcessById(pid);
Oops, something went wrong.

0 comments on commit f933c70

Please sign in to comment.