@@ -1050,6 +1050,23 @@ void ScriptInterpreterPythonImpl::ExecuteInterpreterLoop() {
1050
1050
}
1051
1051
1052
1052
bool ScriptInterpreterPythonImpl::Interrupt () {
1053
+ // PyErr_SetInterrupt was introduced in 3.2.
1054
+ #if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 2) || (PY_MAJOR_VERSION > 3)
1055
+ // If the interpreter isn't evaluating any Python at the moment then return
1056
+ // false to signal that this function didn't handle the interrupt and the
1057
+ // next component should try handling it.
1058
+ if (!IsExecutingPython ())
1059
+ return false ;
1060
+
1061
+ // Tell Python that it should pretend to have received a SIGINT.
1062
+ PyErr_SetInterrupt ();
1063
+ // PyErr_SetInterrupt has no way to return an error so we can only pretend the
1064
+ // signal got successfully handled and return true.
1065
+ // Python 3.10 introduces PyErr_SetInterruptEx that could return an error, but
1066
+ // the error handling is limited to checking the arguments which would be
1067
+ // just our (hardcoded) input signal code SIGINT, so that's not useful at all.
1068
+ return true ;
1069
+ #else
1053
1070
Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT));
1054
1071
1055
1072
if (IsExecutingPython ()) {
@@ -1071,6 +1088,7 @@ bool ScriptInterpreterPythonImpl::Interrupt() {
1071
1088
" ScriptInterpreterPythonImpl::Interrupt() python code not running, "
1072
1089
" can't interrupt" );
1073
1090
return false ;
1091
+ #endif
1074
1092
}
1075
1093
1076
1094
bool ScriptInterpreterPythonImpl::ExecuteOneLineWithReturn (
@@ -3276,6 +3294,28 @@ ScriptInterpreterPythonImpl::AcquireInterpreterLock() {
3276
3294
return py_lock;
3277
3295
}
3278
3296
3297
+ namespace {
3298
+ // / Saves the current signal handler for the specified signal and restores
3299
+ // / it at the end of the current scope.
3300
+ struct RestoreSignalHandlerScope {
3301
+ // / The signal handler.
3302
+ struct sigaction m_prev_handler;
3303
+ int m_signal_code;
3304
+ RestoreSignalHandlerScope (int signal_code) : m_signal_code(signal_code) {
3305
+ // Initialize sigaction to their default state.
3306
+ std::memset (&m_prev_handler, 0 , sizeof (m_prev_handler));
3307
+ // Don't install a new handler, just read back the old one.
3308
+ struct sigaction *new_handler = nullptr ;
3309
+ int signal_err = ::sigaction (m_signal_code, new_handler, &m_prev_handler);
3310
+ lldbassert (signal_err == 0 && " sigaction failed to read handler" );
3311
+ }
3312
+ ~RestoreSignalHandlerScope () {
3313
+ int signal_err = ::sigaction (m_signal_code, &m_prev_handler, nullptr );
3314
+ lldbassert (signal_err == 0 && " sigaction failed to restore old handler" );
3315
+ }
3316
+ };
3317
+ } // namespace
3318
+
3279
3319
void ScriptInterpreterPythonImpl::InitializePrivate () {
3280
3320
if (g_initialized)
3281
3321
return ;
@@ -3311,6 +3351,25 @@ void ScriptInterpreterPythonImpl::InitializePrivate() {
3311
3351
" lldb.embedded_interpreter; from "
3312
3352
" lldb.embedded_interpreter import run_python_interpreter; "
3313
3353
" from lldb.embedded_interpreter import run_one_line" );
3354
+
3355
+ #if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 2) || (PY_MAJOR_VERSION > 3)
3356
+ // Python will not just overwrite its internal SIGINT handler but also the
3357
+ // one from the process. Backup the current SIGINT handler to prevent that
3358
+ // Python deletes it.
3359
+ RestoreSignalHandlerScope save_sigint (SIGINT);
3360
+
3361
+ // Setup a default SIGINT signal handler that works the same way as the
3362
+ // normal Python REPL signal handler which raises a KeyboardInterrupt.
3363
+ // Also make sure to not pollute the user's REPL with the signal module nor
3364
+ // our utility function.
3365
+ PyRun_SimpleString (" def lldb_setup_sigint_handler():\n "
3366
+ " import signal;\n "
3367
+ " def signal_handler(sig, frame):\n "
3368
+ " raise KeyboardInterrupt()\n "
3369
+ " signal.signal(signal.SIGINT, signal_handler);\n "
3370
+ " lldb_setup_sigint_handler();\n "
3371
+ " del lldb_setup_sigint_handler\n " );
3372
+ #endif
3314
3373
}
3315
3374
3316
3375
void ScriptInterpreterPythonImpl::AddToSysPath (AddLocation location,
0 commit comments