Allow python command interpreter commands to be interruptable via CTRL+C.

<rdar://problem/17935601>

llvm-svn: 227163
This commit is contained in:
Greg Clayton 2015-01-27 01:58:22 +00:00
parent d649c0ad56
commit e507bce2de
4 changed files with 68 additions and 20 deletions

View File

@ -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,

View File

@ -40,6 +40,9 @@ public:
~ScriptInterpreterPython ();
bool
Interrupt() override;
bool
ExecuteOneLine (const char *command,
CommandReturnObject *result,
@ -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

View File

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

View File

@ -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
@ -869,6 +855,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,