Skip to content
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
30 changes: 30 additions & 0 deletions eng/scripts/generate_os_codes.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,34 @@ def generate_TIOC_commands(cw):
generate_codes(cw, codeval, 'public', hex, unix_only=True)


# python3 -c 'import signal;print(dict(sorted((s, int(getattr(signal, s))) for s in dir(signal) if s.startswith("SIG") and not s.startswith("SIG_"))))'
# Python 3.12.3 [GCC 13.3.0] on linux 6.8.0
SIG_codes_linux = {'SIGABRT': 6, 'SIGALRM': 14, 'SIGBUS': 7, 'SIGCHLD': 17, 'SIGCLD': 17, 'SIGCONT': 18, 'SIGFPE': 8, 'SIGHUP': 1, 'SIGILL': 4, 'SIGINT': 2, 'SIGIO': 29, 'SIGIOT': 6, 'SIGKILL': 9, 'SIGPIPE': 13, 'SIGPOLL': 29, 'SIGPROF': 27, 'SIGPWR': 30, 'SIGQUIT': 3, 'SIGRTMAX': 64, 'SIGRTMIN': 34, 'SIGSEGV': 11, 'SIGSTKFLT': 16, 'SIGSTOP': 19, 'SIGSYS': 31, 'SIGTERM': 15, 'SIGTRAP': 5, 'SIGTSTP': 20, 'SIGTTIN': 21, 'SIGTTOU': 22, 'SIGURG': 23, 'SIGUSR1': 10, 'SIGUSR2': 12, 'SIGVTALRM': 26, 'SIGWINCH': 28, 'SIGXCPU': 24, 'SIGXFSZ': 25}
# Python 3.9.6 [Clang 17.0.0] on darwin 24.3.0
SIG_codes_darwin = {'SIGABRT': 6, 'SIGALRM': 14, 'SIGBUS': 10, 'SIGCHLD': 20, 'SIGCONT': 19, 'SIGEMT': 7, 'SIGFPE': 8, 'SIGHUP': 1, 'SIGILL': 4, 'SIGINFO': 29, 'SIGINT': 2, 'SIGIO': 23, 'SIGIOT': 6, 'SIGKILL': 9, 'SIGPIPE': 13, 'SIGPROF': 27, 'SIGQUIT': 3, 'SIGSEGV': 11, 'SIGSTOP': 17, 'SIGSYS': 12, 'SIGTERM': 15, 'SIGTRAP': 5, 'SIGTSTP': 18, 'SIGTTIN': 21, 'SIGTTOU': 22, 'SIGURG': 16, 'SIGUSR1': 30, 'SIGUSR2': 31, 'SIGVTALRM': 26, 'SIGWINCH': 28, 'SIGXCPU': 24, 'SIGXFSZ': 25}
# Python 3.6.8 [MSC v.1916 64 bit (AMD64)] on win32
SIG_codes_windows = {'SIGABRT': 22, 'SIGBREAK': 21, 'SIGFPE': 8, 'SIGILL': 4, 'SIGINT': 2, 'SIGSEGV': 11, 'SIGTERM': 15}

def generate_signal_codes(cw):
codeval = {}
for idx, SIG_codes in [(linux_idx, SIG_codes_linux), (darwin_idx, SIG_codes_darwin), (windows_idx, SIG_codes_windows)]:
for name in SIG_codes:
set_value(codeval, name, SIG_codes[name], idx)
codeval = OrderedDict(sorted(codeval.items()))
generate_codes(cw, codeval, 'public', str)


def generate_supported_signals(cw):
for system, SIG_codes in [("Linux", SIG_codes_linux), ("MacOS", SIG_codes_darwin), ("Windows", SIG_codes_windows)]:
cw.writeline(f'[SupportedOSPlatform("{system.lower()}")]')
cw.writeline(f'private static readonly int[] _PySupportedSignals_{system} = [')
cw.indent()
cw.writeline(', '.join(sorted(SIG_codes)))
cw.dedent()
cw.writeline('];')
cw.writeline()


def main():
return generate(
("Errno Codes", generate_errno_codes),
Expand All @@ -315,6 +343,8 @@ def main():
("Directory Notify Flags", generate_DN_flags),
("LOCK Flags", generate_LOCK_flags),
("TIOC Commands", generate_TIOC_commands),
("Signal Codes", generate_signal_codes),
("Supported Signals", generate_supported_signals),
)

if __name__ == "__main__":
Expand Down
12 changes: 7 additions & 5 deletions src/core/IronPython.Modules/SimpleSignalState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#if FEATURE_PROCESS

using System;
using System.Runtime.InteropServices;

using IronPython.Runtime;

Expand All @@ -21,11 +22,12 @@ public SimpleSignalState(PythonContext pc)


private void Console_CancelKeyPress(object? sender, ConsoleCancelEventArgs e) {
int pySignal = e.SpecialKey switch {
ConsoleSpecialKey.ControlC => SIGINT,
ConsoleSpecialKey.ControlBreak => SIGBREAK,
_ => throw new InvalidOperationException("unreachable"),
};
int pySignal = !RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? SIGINT
: e.SpecialKey switch {
ConsoleSpecialKey.ControlC => SIGINT,
ConsoleSpecialKey.ControlBreak => SIGBREAK,
_ => throw new InvalidOperationException("unreachable"),
};

lock (PySignalToPyHandler) {
if (PySignalToPyHandler[pySignal].GetType() == typeof(int)) {
Expand Down
261 changes: 236 additions & 25 deletions src/core/IronPython.Modules/signal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,19 +87,191 @@ private static PythonSignalState MakeSimpleSignalState(PythonContext context) {
}


//Python signals
public const int NSIG = 23;
public const int SIGABRT = 22;
public const int SIGBREAK = 21;
public const int SIGFPE = 8;
public const int SIGILL = 4;
public const int SIGINT = 2;
public const int SIGSEGV = 11;
public const int SIGTERM = 15;
#region Generated Signal Codes

// *** BEGIN GENERATED CODE ***
// generated by function: generate_signal_codes from: generate_os_codes.py


public static int SIGABRT => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? 22 : 6;

[PythonHidden(PlatformsAttribute.PlatformFamily.Windows)]
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("macos")]
public static int SIGALRM => 14;

[PythonHidden(PlatformsAttribute.PlatformFamily.Unix)]
[SupportedOSPlatform("windows")]
public static int SIGBREAK => 21;

[PythonHidden(PlatformsAttribute.PlatformFamily.Windows)]
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("macos")]
public static int SIGBUS => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 10 : 7;

[PythonHidden(PlatformsAttribute.PlatformFamily.Windows)]
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("macos")]
public static int SIGCHLD => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 20 : 17;

[PythonHidden(PlatformsAttribute.PlatformFamily.Windows, PlatformID.MacOSX)]
[SupportedOSPlatform("linux")]
public static int SIGCLD => 17;

[PythonHidden(PlatformsAttribute.PlatformFamily.Windows)]
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("macos")]
public static int SIGCONT => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 19 : 18;

[PythonHidden(PlatformsAttribute.PlatformFamily.Windows, PlatformID.Unix)]
[SupportedOSPlatform("macos")]
public static int SIGEMT => 7;

public static int SIGFPE => 8;

[PythonHidden(PlatformsAttribute.PlatformFamily.Windows)]
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("macos")]
public static int SIGHUP => 1;

public static int SIGILL => 4;

[PythonHidden(PlatformsAttribute.PlatformFamily.Windows, PlatformID.Unix)]
[SupportedOSPlatform("macos")]
public static int SIGINFO => 29;

public static int SIGINT => 2;

[PythonHidden(PlatformsAttribute.PlatformFamily.Windows)]
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("macos")]
public static int SIGIO => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 23 : 29;

[PythonHidden(PlatformsAttribute.PlatformFamily.Windows)]
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("macos")]
public static int SIGIOT => 6;

[PythonHidden(PlatformsAttribute.PlatformFamily.Windows)]
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("macos")]
public static int SIGKILL => 9;

[PythonHidden(PlatformsAttribute.PlatformFamily.Windows)]
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("macos")]
public static int SIGPIPE => 13;

[PythonHidden(PlatformsAttribute.PlatformFamily.Windows, PlatformID.MacOSX)]
[SupportedOSPlatform("linux")]
public static int SIGPOLL => 29;

[PythonHidden(PlatformsAttribute.PlatformFamily.Windows)]
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("macos")]
public static int SIGPROF => 27;

[PythonHidden(PlatformsAttribute.PlatformFamily.Windows, PlatformID.MacOSX)]
[SupportedOSPlatform("linux")]
public static int SIGPWR => 30;

[PythonHidden(PlatformsAttribute.PlatformFamily.Windows)]
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("macos")]
public static int SIGQUIT => 3;

[PythonHidden(PlatformsAttribute.PlatformFamily.Windows, PlatformID.MacOSX)]
[SupportedOSPlatform("linux")]
public static int SIGRTMAX => 64;

[PythonHidden(PlatformsAttribute.PlatformFamily.Windows, PlatformID.MacOSX)]
[SupportedOSPlatform("linux")]
public static int SIGRTMIN => 34;

public static int SIGSEGV => 11;

[PythonHidden(PlatformsAttribute.PlatformFamily.Windows, PlatformID.MacOSX)]
[SupportedOSPlatform("linux")]
public static int SIGSTKFLT => 16;

[PythonHidden(PlatformsAttribute.PlatformFamily.Windows)]
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("macos")]
public static int SIGSTOP => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 17 : 19;

[PythonHidden(PlatformsAttribute.PlatformFamily.Windows)]
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("macos")]
public static int SIGSYS => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 12 : 31;

public static int SIGTERM => 15;

[PythonHidden(PlatformsAttribute.PlatformFamily.Windows)]
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("macos")]
public static int SIGTRAP => 5;

[PythonHidden(PlatformsAttribute.PlatformFamily.Windows)]
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("macos")]
public static int SIGTSTP => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 18 : 20;

[PythonHidden(PlatformsAttribute.PlatformFamily.Windows)]
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("macos")]
public static int SIGTTIN => 21;

[PythonHidden(PlatformsAttribute.PlatformFamily.Windows)]
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("macos")]
public static int SIGTTOU => 22;

[PythonHidden(PlatformsAttribute.PlatformFamily.Windows)]
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("macos")]
public static int SIGURG => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 16 : 23;

[PythonHidden(PlatformsAttribute.PlatformFamily.Windows)]
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("macos")]
public static int SIGUSR1 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 30 : 10;

[PythonHidden(PlatformsAttribute.PlatformFamily.Windows)]
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("macos")]
public static int SIGUSR2 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 31 : 12;

[PythonHidden(PlatformsAttribute.PlatformFamily.Windows)]
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("macos")]
public static int SIGVTALRM => 26;

[PythonHidden(PlatformsAttribute.PlatformFamily.Windows)]
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("macos")]
public static int SIGWINCH => 28;

[PythonHidden(PlatformsAttribute.PlatformFamily.Windows)]
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("macos")]
public static int SIGXCPU => 24;

[PythonHidden(PlatformsAttribute.PlatformFamily.Windows)]
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("macos")]
public static int SIGXFSZ => 25;

// *** END GENERATED CODE ***

#endregion

public static int NSIG => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? 23 : RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 32 : 65;

public const int SIG_DFL = 0;
public const int SIG_IGN = 1;

//Windows signals

// Windows signals
[SupportedOSPlatform("windows"), PythonHidden(PlatformsAttribute.PlatformFamily.Unix)]
public const int CTRL_C_EVENT = 0;
[SupportedOSPlatform("windows"), PythonHidden(PlatformsAttribute.PlatformFamily.Unix)]
Expand Down Expand Up @@ -172,10 +344,10 @@ public static object default_int_handlerImpl(int signalnum, TraceBackFrame? fram
""")]
public static object? signal(CodeContext/*!*/ context, int signalnum, object? action) {
// Negative scenarios - signalnum
if (signalnum <= 0 || signalnum >= NSIG) {
throw PythonOps.ValueError("signal number out of range");
} else if (Array.IndexOf(_PySupportedSignals, signalnum) == -1) {
throw new RuntimeException("no IronPython support for given signal");
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
if (Array.IndexOf(_PySupportedSignals_Windows, signalnum) == -1) throw PythonOps.ValueError("invalid signal value");
} else {
if (signalnum <= 0 || signalnum >= NSIG) throw PythonOps.ValueError("signal number out of range");
}
// Negative scenarios - action
if (action == null) {
Expand All @@ -198,10 +370,15 @@ public static object default_int_handlerImpl(int signalnum, TraceBackFrame? fram
}
}

if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) {
// These signals cannot be handled
if (signalnum == SIGKILL || signalnum == SIGSTOP) throw PythonNT.GetOsError(PythonErrno.EINVAL);
}
object? last_handler = null;
lock (GetPythonSignalState(context).PySignalToPyHandler) {
// CPython returns the previous handler for the signal
last_handler = getsignal(context, signalnum);
if (last_handler is null) throw PythonNT.GetOsError(PythonErrno.EINVAL);
// Set the new action
GetPythonSignalState(context).PySignalToPyHandler[signalnum] = action;
}
Expand Down Expand Up @@ -250,20 +427,54 @@ private class PythonSignalState {

public PythonSignalState(PythonContext pc) {
SignalPythonContext = pc;
PySignalToPyHandler = new Dictionary<int, object>() {
{ SIGABRT, SIG_DFL},
{ SIGBREAK, SIG_DFL},
{ SIGFPE, SIG_DFL},
{ SIGILL, SIG_DFL},
{ SIGINT, default_int_handler},
{ SIGSEGV, SIG_DFL},
{ SIGTERM, SIG_DFL},
};
int[] sigs = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? _PySupportedSignals_Windows
: RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? _PySupportedSignals_MacOS
: RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? _PySupportedSignals_Linux
: throw new NotSupportedException("Unsupported platform for signal module");

PySignalToPyHandler = new Dictionary<int, object>(sigs.Length);
object sig_dfl = ScriptingRuntimeHelpers.Int32ToObject(SIG_DFL);
object sig_ign = ScriptingRuntimeHelpers.Int32ToObject(SIG_IGN);
foreach (int sig in sigs) {
PySignalToPyHandler[sig] = sig_dfl;
}
PySignalToPyHandler[SIGINT] = default_int_handler;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) {
PySignalToPyHandler[SIGPIPE] = sig_ign;
PySignalToPyHandler[SIGXFSZ] = sig_ign;
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) {
PySignalToPyHandler.Remove(SIGKILL);
PySignalToPyHandler.Remove(SIGSTOP);
}
}
}

// 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 };

#region Generated Supported Signals

// *** BEGIN GENERATED CODE ***
// generated by function: generate_supported_signals from: generate_os_codes.py

[SupportedOSPlatform("linux")]
private static readonly int[] _PySupportedSignals_Linux = [
SIGABRT, SIGALRM, SIGBUS, SIGCHLD, SIGCLD, SIGCONT, SIGFPE, SIGHUP, SIGILL, SIGINT, SIGIO, SIGIOT, SIGKILL, SIGPIPE, SIGPOLL, SIGPROF, SIGPWR, SIGQUIT, SIGRTMAX, SIGRTMIN, SIGSEGV, SIGSTKFLT, SIGSTOP, SIGSYS, SIGTERM, SIGTRAP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGUSR1, SIGUSR2, SIGVTALRM, SIGWINCH, SIGXCPU, SIGXFSZ
];

[SupportedOSPlatform("macos")]
private static readonly int[] _PySupportedSignals_MacOS = [
SIGABRT, SIGALRM, SIGBUS, SIGCHLD, SIGCONT, SIGEMT, SIGFPE, SIGHUP, SIGILL, SIGINFO, SIGINT, SIGIO, SIGIOT, SIGKILL, SIGPIPE, SIGPROF, SIGQUIT, SIGSEGV, SIGSTOP, SIGSYS, SIGTERM, SIGTRAP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGUSR1, SIGUSR2, SIGVTALRM, SIGWINCH, SIGXCPU, SIGXFSZ
];

[SupportedOSPlatform("windows")]
private static readonly int[] _PySupportedSignals_Windows = [
SIGABRT, SIGBREAK, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM
];


// *** END GENERATED CODE ***

#endregion

// Signature of Python functions that signal.signal(...) expects to be given
private delegate object PySignalHandler(int signalnum, TraceBackFrame? frame);
Expand Down
Loading