diff options
4 files changed, 68 insertions, 20 deletions
diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreter.h b/lldb/include/lldb/Interpreter/ScriptInterpreter.h index 35ba9491ded..6cf5b6d4530 100644 --- a/lldb/include/lldb/Interpreter/ScriptInterpreter.h +++ b/lldb/include/lldb/Interpreter/ScriptInterpreter.h @@ -240,7 +240,13 @@ public: bool m_set_lldb_globals; bool m_maskout_errors; }; - + + virtual bool + Interrupt() + { + return false; + } + virtual bool ExecuteOneLine (const char *command, CommandReturnObject *result, diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h b/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h index edcc4c44fac..a0686e03aeb 100644 --- a/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h +++ b/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h @@ -41,6 +41,9 @@ public: ~ScriptInterpreterPython (); bool + Interrupt() override; + + bool ExecuteOneLine (const char *command, CommandReturnObject *result, const ExecuteScriptOptions &options = ExecuteScriptOptions()); @@ -448,6 +451,26 @@ public: }; protected: + uint32_t + IsExecutingPython () const + { + return m_lock_count > 0; + } + + uint32_t + IncrementLockCount() + { + return ++m_lock_count; + } + + uint32_t + DecrementLockCount() + { + if (m_lock_count > 0) + --m_lock_count; + return m_lock_count; + } + enum ActiveIOHandler { eIOHandlerNone, eIOHandlerBreakpoint, @@ -480,6 +503,7 @@ protected: bool m_session_is_active; bool m_pty_slave_is_open; bool m_valid_session; + uint32_t m_lock_count; PyThreadState *m_command_thread_state; }; } // namespace lldb_private diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index 2729c65525f..6318b80a29e 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -3229,6 +3229,13 @@ CommandInterpreter::IOHandlerInterrupt (IOHandler &io_handler) return true; // Don't do any updating when we are running } } + + ScriptInterpreter *script_interpreter = GetScriptInterpreter (false); + if (script_interpreter) + { + if (script_interpreter->Interrupt()) + return true; + } return false; } diff --git a/lldb/source/Interpreter/ScriptInterpreterPython.cpp b/lldb/source/Interpreter/ScriptInterpreterPython.cpp index ab151073f9e..719f966ace9 100644 --- a/lldb/source/Interpreter/ScriptInterpreterPython.cpp +++ b/lldb/source/Interpreter/ScriptInterpreterPython.cpp @@ -103,13 +103,14 @@ ScriptInterpreterPython::Locker::DoAcquireLock() m_GILState = PyGILState_Ensure(); if (log) log->Printf("Ensured PyGILState. Previous state = %slocked\n", m_GILState == PyGILState_UNLOCKED ? "un" : ""); - + // we need to save the thread state when we first start the command // because we might decide to interrupt it while some action is taking // place outside of Python (e.g. printing to screen, waiting for the network, ...) // in that case, _PyThreadState_Current will be NULL - and we would be unable // to set the asynchronous exception - not a desirable situation m_python_interpreter->SetThreadState (_PyThreadState_Current); + m_python_interpreter->IncrementLockCount(); return true; } @@ -128,6 +129,7 @@ ScriptInterpreterPython::Locker::DoFreeLock() if (log) log->Printf("Releasing PyGILState. Returning to state = %slocked\n", m_GILState == PyGILState_UNLOCKED ? "un" : ""); PyGILState_Release(m_GILState); + m_python_interpreter->DecrementLockCount(); return true; } @@ -166,6 +168,7 @@ ScriptInterpreterPython::ScriptInterpreterPython (CommandInterpreter &interprete m_session_is_active (false), m_pty_slave_is_open (false), m_valid_session (true), + m_lock_count (0), m_command_thread_state (nullptr) { @@ -817,24 +820,7 @@ public: virtual bool Interrupt () { - Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT)); - - PyThreadState* state = _PyThreadState_Current; - if (!state) - state = m_python->GetThreadState(); - if (state) - { - long tid = state->thread_id; - _PyThreadState_Current = state; - int num_threads = PyThreadState_SetAsyncExc(tid, PyExc_KeyboardInterrupt); - if (log) - log->Printf("ScriptInterpreterPython::NonInteractiveInputReaderCallback, eInputReaderInterrupt, tid = %ld, num_threads = %d, state = %p", - tid, num_threads, static_cast<void *>(state)); - } - else if (log) - log->Printf("ScriptInterpreterPython::NonInteractiveInputReaderCallback, eInputReaderInterrupt, state = NULL"); - - return false; + return m_python->Interrupt(); } virtual void @@ -870,6 +856,31 @@ ScriptInterpreterPython::ExecuteInterpreterLoop () } bool +ScriptInterpreterPython::Interrupt() +{ + Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT)); + + if (IsExecutingPython()) + { + PyThreadState* state = _PyThreadState_Current; + if (!state) + state = GetThreadState(); + if (state) + { + long tid = state->thread_id; + _PyThreadState_Current = state; + int num_threads = PyThreadState_SetAsyncExc(tid, PyExc_KeyboardInterrupt); + if (log) + log->Printf("ScriptInterpreterPython::Interrupt() sending PyExc_KeyboardInterrupt (tid = %li, num_threads = %i)...", tid, num_threads); + return true; + } + } + if (log) + log->Printf("ScriptInterpreterPython::Interrupt() python code not running, can't interrupt"); + return false; + +} +bool ScriptInterpreterPython::ExecuteOneLineWithReturn (const char *in_string, ScriptInterpreter::ScriptReturnType return_type, void *ret_value, |