Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
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...
commit f933c70552576ef0cc772f2b3afc120492ae1fbc 1 parent 8cfc05a
@jdhardy authored
View
3  Languages/IronPython/IronPython.Modules/IronPython.Modules.csproj
@@ -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" />
View
34 Languages/IronPython/IronPython.Modules/NativeSignal.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
-}
View
129 Languages/IronPython/IronPython.Modules/NtSignalState.cs
@@ -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
View
85 Languages/IronPython/IronPython.Modules/SimpleSignalState.cs
@@ -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
+
View
19 Languages/IronPython/IronPython.Modules/nt.cs
@@ -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);
View
128 Languages/IronPython/IronPython.Modules/signal.cs
@@ -27,11 +27,11 @@
using Microsoft.Scripting.Runtime;
using Microsoft.Scripting.Utils;
-#if !SILVERLIGHT
+#if FEATURE_PROCESS
[assembly: PythonModule("signal", typeof(IronPython.Modules.PythonSignal))]
namespace IronPython.Modules {
- public static class PythonSignal {
+ public static partial class PythonSignal {
public const string __doc__ = @"This module provides mechanisms to use signal handlers in Python.
Functions:
@@ -52,12 +52,28 @@ public static class PythonSignal {
[SpecialName]
public static void PerformModuleReload(PythonContext/*!*/ context, PythonDictionary/*!*/ dict) {
- PythonSignalState pss = new PythonSignalState(context);
- context.SetModuleState(_PythonSignalStateKey, pss);
- NativeSignal.SetConsoleCtrlHandler(pss.WinAllSignalsHandlerDelegate, true);
+ context.SetModuleState(_PythonSignalStateKey, MakeSignalState(context));
}
- #region Public API
+ private static PythonSignalState MakeSignalState(PythonContext context) {
+ if (Environment.OSVersion.Platform == PlatformID.Unix
+ || Environment.OSVersion.Platform == PlatformID.MacOSX) {
+ return MakePosixSignalState(context);
+ } else {
+ return MakeNtSignalState(context);
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static PythonSignalState MakeNtSignalState(PythonContext context) {
+ return new NtSignalState(context);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static PythonSignalState MakePosixSignalState(PythonContext context) {
+ // Use SimpleSignalState until the real Posix one is written
+ return new SimpleSignalState(context);
+ }
//Python signals
public const int NSIG = 23;
@@ -71,13 +87,6 @@ public static class PythonSignal {
public const int SIG_DFL = 0;
public const int SIG_IGN = 1;
- //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;
-
public static BuiltinFunction default_int_handler = BuiltinFunction.MakeFunction("default_int_handler",
ArrayUtils.ConvertAll(typeof(PythonSignal).GetMember("default_int_handlerImpl"), (x) => (MethodBase)x),
typeof(PythonSignal)
@@ -126,7 +135,7 @@ public static class PythonSignal {
the first is the signal number, the second is the interrupted stack frame.")]
public static object signal(CodeContext/*!*/ context, int sig, object action) {
//Negative scenarios - sig
- if (sig < 1 || sig > 22) {
+ if (sig < 1 || sig >= NSIG) {
throw PythonOps.ValueError("signal number out of range");
} else if (Array.IndexOf(_PySupportedSignals, sig) == -1) {
throw new RuntimeException("no IronPython support for given signal");
@@ -176,33 +185,25 @@ public static class PythonSignal {
throw new NotImplementedException(); //TODO
}
-
- #endregion
-
- #region Private implementation details
-
private static readonly object _PythonSignalStateKey = new object();
+
private static PythonSignalState GetPythonSignalState(CodeContext/*!*/ context) {
return (PythonSignalState)PythonContext.GetContext(context).GetModuleState(_PythonSignalStateKey);
}
+
private static void SetPythonSignalState(CodeContext/*!*/ context, PythonSignalState pss) {
PythonContext.GetContext(context).SetModuleState(_PythonSignalStateKey, pss);
}
- private class PythonSignalState {
+ internal class PythonSignalState {
//this provides us with access to the Main thread's stack
public PythonContext SignalPythonContext;
//Map out signal identifiers to their actual handlers
public Dictionary<int, object> PySignalToPyHandler;
- //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 PythonSignalState(PythonContext pc) {
SignalPythonContext = pc;
- WinAllSignalsHandlerDelegate = new NativeSignal.WinSignalsHandler(WindowsEventHandler);
PySignalToPyHandler = new Dictionary<int, object>() {
{ SIGABRT, SIG_DFL},
{ SIGBREAK, SIG_DFL},
@@ -213,90 +214,13 @@ private class PythonSignalState {
{ SIGTERM, SIG_DFL},
};
}
-
- //Our implementation of WinSignalsHandler
- public 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;
- }
}
-
-
//List of all Signals CPython supports on Windows. Notice the addition of '6'
private static readonly int[] _PySupportedSignals = { SIGABRT, SIGBREAK, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM, 6 };
//Signature of Python functions that signal.signal(...) expects to be given
private delegate object PySignalHandler(int signalnum, TraceBackFrame frame);
-
-
- #endregion
}
}
Please sign in to comment.
Something went wrong with that request. Please try again.