Decoupling of lock-related code from the core of ScriptInterpreterPython. All that concerns locking the Python interpreter is now delegated to the internal ScriptInterpreterPython::Locker class. Several changes in ScriptInterpreterPython to accommodate this new pattern.

llvm-svn: 142802
This commit is contained in:
Enrico Granata 2011-10-24 17:22:21 +00:00
parent 1b5e49a35a
commit 47c6f6d43d
2 changed files with 162 additions and 235 deletions

View File

@ -161,19 +161,50 @@ private:
class Locker
{
public:
Locker (ScriptInterpreterPython *py_interpreter,
FILE* wait_msg_handle = NULL,
bool need_session = true);
bool
HasAcquiredLock ()
enum OnEntry
{
return m_release_lock;
}
AcquireLock = 0x0001,
InitSession = 0x0002
};
enum OnLeave
{
FreeLock = 0x0001,
FreeAcquiredLock = 0x0002, // do not free the lock if we already held it when calling constructor
TearDownSession = 0x0004
};
Locker (ScriptInterpreterPython *py_interpreter = NULL,
uint16_t on_entry = AcquireLock | InitSession,
uint16_t on_leave = FreeLock | TearDownSession,
FILE* wait_msg_handle = NULL);
~Locker ();
static bool
CurrentThreadHasPythonLock ();
private:
bool
DoAcquireLock ();
bool
DoInitSession ();
bool
DoFreeLock ();
bool
DoTearDownSession ();
static bool
TryGetPythonLock (uint32_t seconds_to_wait);
static void
ReleasePythonLock ();
bool m_need_session;
bool m_release_lock;
ScriptInterpreterPython *m_python_interpreter;

View File

@ -63,8 +63,8 @@ PythonMutexPredicate ()
return g_interpreter_is_running;
}
static bool
CurrentThreadHasPythonLock ()
bool
ScriptInterpreterPython::Locker::CurrentThreadHasPythonLock ()
{
TimeValue timeout;
@ -73,8 +73,8 @@ CurrentThreadHasPythonLock ()
return PythonMutexPredicate().WaitForValueEqualTo (Host::GetCurrentThreadID(), &timeout, NULL);
}
static bool
GetPythonLock (uint32_t seconds_to_wait)
bool
ScriptInterpreterPython::Locker::TryGetPythonLock (uint32_t seconds_to_wait)
{
TimeValue timeout;
@ -89,40 +89,88 @@ GetPythonLock (uint32_t seconds_to_wait)
Host::GetCurrentThreadID(), &timeout, NULL);
}
static void
ReleasePythonLock ()
void
ScriptInterpreterPython::Locker::ReleasePythonLock ()
{
PythonMutexPredicate().SetValue (LLDB_INVALID_THREAD_ID, eBroadcastAlways);
}
ScriptInterpreterPython::Locker::Locker (ScriptInterpreterPython *pi,
FILE* tmp_fh,
bool ns) :
m_need_session(ns),
m_release_lock(false),
m_python_interpreter(pi),
m_tmp_fh(tmp_fh)
ScriptInterpreterPython::Locker::Locker (ScriptInterpreterPython *py_interpreter,
uint16_t on_entry,
uint16_t on_leave,
FILE* wait_msg_handle) :
m_need_session( (on_leave & TearDownSession) == TearDownSession ),
m_release_lock ( false ), // decide in constructor body
m_python_interpreter(py_interpreter),
m_tmp_fh(wait_msg_handle)
{
// if Enter/LeaveSession() must be called, then m_python_interpreter must be != NULL
assert(m_need_session && m_python_interpreter);
if (!CurrentThreadHasPythonLock())
if (m_python_interpreter && !m_tmp_fh)
m_tmp_fh = (m_python_interpreter->m_dbg_stdout ? m_python_interpreter->m_dbg_stdout : stdout);
if ( (on_entry & AcquireLock) == AcquireLock )
{
while (!GetPythonLock (1))
if (tmp_fh)
fprintf (tmp_fh,
"Python interpreter locked on another thread; waiting to acquire lock...\n");
if (CurrentThreadHasPythonLock())
{
if ( (on_leave & FreeLock) == FreeLock )
m_release_lock = true;
}
if (m_need_session)
else
{
DoAcquireLock();
if ( (on_leave & FreeLock) == FreeLock )
m_release_lock = true;
if ( (on_leave & FreeAcquiredLock) == FreeAcquiredLock )
m_release_lock = true;
}
}
if ( (on_entry & InitSession) == InitSession )
DoInitSession();
}
bool
ScriptInterpreterPython::Locker::DoAcquireLock()
{
if (!CurrentThreadHasPythonLock())
{
while (!TryGetPythonLock (1))
if (m_tmp_fh)
fprintf (m_tmp_fh,
"Python interpreter locked on another thread; waiting to acquire lock...\n");
}
return true;
}
bool
ScriptInterpreterPython::Locker::DoInitSession()
{
if (!m_python_interpreter)
return false;
m_python_interpreter->EnterSession ();
return true;
}
bool
ScriptInterpreterPython::Locker::DoFreeLock()
{
ReleasePythonLock ();
return true;
}
bool
ScriptInterpreterPython::Locker::DoTearDownSession()
{
if (!m_python_interpreter)
return false;
m_python_interpreter->LeaveSession ();
return true;
}
ScriptInterpreterPython::Locker::~Locker()
{
if (m_need_session)
m_python_interpreter->LeaveSession ();
DoTearDownSession();
if (m_release_lock)
ReleasePythonLock ();
DoFreeLock();
}
ScriptInterpreterPython::ScriptInterpreterPython (CommandInterpreter &interpreter) :
@ -146,31 +194,9 @@ ScriptInterpreterPython::ScriptInterpreterPython (CommandInterpreter &interprete
ScriptInterpreterPython::InitializePrivate ();
}
bool safe_to_run = false;
bool need_to_release_lock = true;
int interval = 5; // Number of seconds to try getting the Python lock before timing out.
// We don't dare exit this function without finishing setting up the script interpreter, so we must wait until
// we can get the Python lock.
if (CurrentThreadHasPythonLock())
{
safe_to_run = true;
need_to_release_lock = false;
}
while (!safe_to_run)
{
safe_to_run = GetPythonLock (interval);
if (!safe_to_run)
{
FILE *tmp_fh = (m_dbg_stdout ? m_dbg_stdout : stdout);
fprintf (tmp_fh,
"Python interpreter is locked on another thread; "
"please release interpreter in order to continue.\n");
interval = interval * 2;
}
}
Locker locker(this,
ScriptInterpreterPython::Locker::AcquireLock,
ScriptInterpreterPython::Locker::FreeAcquiredLock);
m_dictionary_name.append("_dict");
StreamString run_string;
@ -221,9 +247,6 @@ ScriptInterpreterPython::ScriptInterpreterPython (CommandInterpreter &interprete
{
m_new_sysout = PyFile_FromFile (m_dbg_stdout, (char *) "", (char *) "w", _check_and_flush);
}
if (need_to_release_lock)
ReleasePythonLock();
}
ScriptInterpreterPython::~ScriptInterpreterPython ()
@ -242,15 +265,9 @@ ScriptInterpreterPython::~ScriptInterpreterPython ()
if (m_new_sysout)
{
FILE *tmp_fh = (m_dbg_stdout ? m_dbg_stdout : stdout);
if (!CurrentThreadHasPythonLock ())
{
while (!GetPythonLock (1))
fprintf (tmp_fh, "Python interpreter locked on another thread; waiting to acquire lock...\n");
Py_DECREF ((PyObject*)m_new_sysout);
ReleasePythonLock ();
}
else
Locker locker(this,
ScriptInterpreterPython::Locker::AcquireLock,
ScriptInterpreterPython::Locker::FreeLock);
Py_DECREF ((PyObject*)m_new_sysout);
}
}
@ -263,9 +280,7 @@ ScriptInterpreterPython::ResetOutputFileHandle (FILE *fh)
m_dbg_stdout = fh;
FILE *tmp_fh = (m_dbg_stdout ? m_dbg_stdout : stdout);
Locker py_lock(this, tmp_fh);
Locker py_lock(this);
m_new_sysout = PyFile_FromFile (m_dbg_stdout, (char *) "", (char *) "w", _check_and_flush);
}
@ -290,8 +305,6 @@ ScriptInterpreterPython::RestoreTerminalState ()
m_terminal_state.Restore();
}
void
ScriptInterpreterPython::LeaveSession ()
{
@ -389,26 +402,15 @@ ScriptInterpreterPython::ExecuteOneLine (const char *command, CommandReturnObjec
if (!m_valid_session)
return false;
// We want to call run_one_line, passing in the dictionary and the command string. We cannot do this through
// PyRun_SimpleString here because the command string may contain escaped characters, and putting it inside
// another string to pass to PyRun_SimpleString messes up the escaping. So we use the following more complicated
// method to pass the command string directly down to Python.
Locker locker(this,
ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession,
ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession);
bool need_to_release_lock = true;
if (CurrentThreadHasPythonLock())
need_to_release_lock = false;
else if (!GetPythonLock (1))
{
fprintf ((m_dbg_stdout ? m_dbg_stdout : stdout),
"Python interpreter is currently locked by another thread; unable to process command.\n");
return false;
}
EnterSession ();
bool success = false;
if (command)
@ -492,11 +494,6 @@ ScriptInterpreterPython::ExecuteOneLine (const char *command, CommandReturnObjec
}
}
LeaveSession ();
if (need_to_release_lock)
ReleasePythonLock();
if (success)
return true;
@ -506,18 +503,11 @@ ScriptInterpreterPython::ExecuteOneLine (const char *command, CommandReturnObjec
return false;
}
LeaveSession ();
if (need_to_release_lock)
ReleasePythonLock ();
if (result)
result->AppendError ("empty command passed to python\n");
return false;
}
size_t
ScriptInterpreterPython::InputReaderCallback
(
@ -559,18 +549,11 @@ ScriptInterpreterPython::InputReaderCallback
script_interpreter->SaveTerminalState(input_fd);
if (!CurrentThreadHasPythonLock())
{
while (!GetPythonLock(1))
{
out_stream->Printf ("Python interpreter locked on another thread; waiting to acquire lock...\n");
out_stream->Flush();
ScriptInterpreterPython::Locker locker(script_interpreter,
ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession,
ScriptInterpreterPython::Locker::FreeAcquiredLock);
}
script_interpreter->EnterSession ();
ReleasePythonLock();
}
else
script_interpreter->EnterSession ();
char error_str[1024];
if (script_interpreter->m_embedded_python_pty.OpenFirstAvailableMaster (O_RDWR|O_NOCTTY, error_str,
@ -610,17 +593,11 @@ ScriptInterpreterPython::InputReaderCallback
break;
case eInputReaderReactivate:
if (!CurrentThreadHasPythonLock())
{
while (!GetPythonLock(1))
{
// Wait until lock is acquired.
ScriptInterpreterPython::Locker locker(script_interpreter,
ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession,
ScriptInterpreterPython::Locker::FreeAcquiredLock);
}
script_interpreter->EnterSession ();
ReleasePythonLock();
}
else
script_interpreter->EnterSession ();
break;
case eInputReaderAsynchronousOutputWritten:
@ -716,18 +693,9 @@ ScriptInterpreterPython::ExecuteOneLineWithReturn (const char *in_string,
void *ret_value)
{
bool need_to_release_lock = true;
if (CurrentThreadHasPythonLock())
need_to_release_lock = false;
else if (!GetPythonLock (1))
{
fprintf ((m_dbg_stdout ? m_dbg_stdout : stdout),
"Python interpreter is currently locked by another thread; unable to process command.\n");
return false;
}
EnterSession ();
Locker locker(this,
ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession,
ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession);
PyObject *py_return = NULL;
PyObject *mainmod = PyImport_AddModule ("__main__");
@ -897,29 +865,17 @@ ScriptInterpreterPython::ExecuteOneLineWithReturn (const char *in_string,
ret_success = false;
}
LeaveSession ();
if (need_to_release_lock)
ReleasePythonLock();
return ret_success;
}
bool
ScriptInterpreterPython::ExecuteMultipleLines (const char *in_string)
{
FILE *tmp_fh = (m_dbg_stdout ? m_dbg_stdout : stdout);
bool need_to_release_lock = true;
if (CurrentThreadHasPythonLock())
need_to_release_lock = false;
else
{
while (!GetPythonLock (1))
fprintf (tmp_fh, "Python interpreter locked on another thread; waiting to acquire lock...\n");
}
EnterSession ();
Locker locker(this,
ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession,
ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession);
bool success = false;
PyObject *py_return = NULL;
@ -990,11 +946,6 @@ ScriptInterpreterPython::ExecuteMultipleLines (const char *in_string)
success = false;
}
LeaveSession ();
if (need_to_release_lock)
ReleasePythonLock();
return success;
}
@ -1303,7 +1254,7 @@ ScriptInterpreterPython::GenerateScriptAliasFunction (StringList &user_input, St
return false;
// Take what the user wrote, wrap it all up inside one big auto-generated Python function, passing in the
// ValueObject as parameter to the function.
// required data as parameters to the function.
sstr.Printf ("lldb_autogen_python_cmd_alias_func_%d", num_created_functions);
++num_created_functions;
@ -1426,10 +1377,8 @@ ScriptInterpreterPython::CreateSyntheticScriptedProvider (std::string class_name
void* ret_val;
FILE *tmp_fh = (python_interpreter->m_dbg_stdout ? python_interpreter->m_dbg_stdout : stdout);
{
Locker py_lock(this, tmp_fh);
Locker py_lock(this);
ret_val = g_swig_synthetic_script (class_name,
python_interpreter->m_dictionary_name.c_str(),
valobj);
@ -1539,10 +1488,8 @@ ScriptInterpreterPython::CallPythonScriptFunction (const char *python_function_n
if (python_function_name
&& *python_function_name)
{
FILE *tmp_fh = (python_interpreter->m_dbg_stdout ? python_interpreter->m_dbg_stdout : stdout);
{
Locker py_lock(python_interpreter, tmp_fh);
Locker py_lock(python_interpreter);
ret_val = g_swig_typescript_callback (python_function_name,
python_interpreter->m_dictionary_name.c_str(),
valobj);
@ -1594,10 +1541,8 @@ ScriptInterpreterPython::BreakpointCallbackFunction
if (stop_frame_sp && bp_loc_sp)
{
bool ret_val = true;
FILE *tmp_fh = (python_interpreter->m_dbg_stdout ? python_interpreter->m_dbg_stdout : stdout);
{
Locker py_lock(python_interpreter, tmp_fh);
Locker py_lock(python_interpreter);
ret_val = g_swig_breakpoint_callback (python_function_name,
python_interpreter->m_dictionary_name.c_str(),
stop_frame_sp,
@ -1624,31 +1569,15 @@ ScriptInterpreterPython::RunEmbeddedPythonInterpreter (lldb::thread_arg_t baton)
char error_str[1024];
const char *pty_slave_name = script_interpreter->m_embedded_python_pty.GetSlaveName (error_str, sizeof (error_str));
bool need_to_release_lock = true;
bool safe_to_run = false;
if (CurrentThreadHasPythonLock())
{
safe_to_run = true;
need_to_release_lock = false;
}
else
{
int interval = 1;
safe_to_run = GetPythonLock (interval);
while (!safe_to_run)
{
interval = interval * 2;
safe_to_run = GetPythonLock (interval);
}
}
Locker locker(script_interpreter,
ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession,
ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession);
if (pty_slave_name != NULL && safe_to_run)
if (pty_slave_name != NULL)
{
StreamString run_string;
script_interpreter->EnterSession ();
run_string.Printf ("run_one_line (%s, 'save_stderr = sys.stderr')", script_interpreter->m_dictionary_name.c_str());
PyRun_SimpleString (run_string.GetData());
run_string.Clear ();
@ -1698,17 +1627,8 @@ ScriptInterpreterPython::RunEmbeddedPythonInterpreter (lldb::thread_arg_t baton)
PyRun_SimpleString (run_string.GetData());
run_string.Clear();
script_interpreter->LeaveSession ();
}
if (!safe_to_run)
fprintf ((script_interpreter->m_dbg_stdout ? script_interpreter->m_dbg_stdout : stdout),
"Python interpreter locked on another thread; unable to acquire lock.\n");
if (need_to_release_lock)
ReleasePythonLock ();
if (script_interpreter->m_embedded_thread_input_reader_sp)
script_interpreter->m_embedded_thread_input_reader_sp->SetIsDone (true);
@ -1739,14 +1659,10 @@ ScriptInterpreterPython::CalculateNumChildren (void *implementor)
if (!g_swig_calc_children)
return 0;
ScriptInterpreterPython *python_interpreter = this;
uint32_t ret_val = 0;
FILE *tmp_fh = (python_interpreter->m_dbg_stdout ? python_interpreter->m_dbg_stdout : stdout);
{
Locker py_lock(python_interpreter, tmp_fh);
Locker py_lock(this);
ret_val = g_swig_calc_children (implementor);
}
@ -1762,16 +1678,12 @@ ScriptInterpreterPython::GetChildAtIndex (void *implementor, uint32_t idx)
if (!g_swig_get_child_index || !g_swig_cast_to_sbvalue)
return lldb::ValueObjectSP();
ScriptInterpreterPython *python_interpreter = this;
void* child_ptr = NULL;
lldb::SBValue* value_sb = NULL;
lldb::ValueObjectSP ret_val;
FILE *tmp_fh = (python_interpreter->m_dbg_stdout ? python_interpreter->m_dbg_stdout : stdout);
{
Locker py_lock(python_interpreter, tmp_fh);
Locker py_lock(this);
child_ptr = g_swig_get_child_index (implementor,idx);
if (child_ptr != NULL && child_ptr != Py_None)
{
@ -1799,14 +1711,10 @@ ScriptInterpreterPython::GetIndexOfChildWithName (void *implementor, const char*
if (!g_swig_get_index_child)
return UINT32_MAX;
ScriptInterpreterPython *python_interpreter = this;
int ret_val = UINT32_MAX;
FILE *tmp_fh = (python_interpreter->m_dbg_stdout ? python_interpreter->m_dbg_stdout : stdout);
{
Locker py_lock(python_interpreter, tmp_fh);
Locker py_lock(this);
ret_val = g_swig_get_index_child (implementor, child_name);
}
@ -1822,12 +1730,8 @@ ScriptInterpreterPython::UpdateSynthProviderInstance (void* implementor)
if (!g_swig_update_provider)
return;
ScriptInterpreterPython *python_interpreter = this;
FILE *tmp_fh = (python_interpreter->m_dbg_stdout ? python_interpreter->m_dbg_stdout : stdout);
{
Locker py_lock(python_interpreter, tmp_fh);
Locker py_lock(this);
g_swig_update_provider (implementor);
}
@ -1850,14 +1754,10 @@ ScriptInterpreterPython::LoadScriptingModule (const char* pathname,
return false;
}
ScriptInterpreterPython *python_interpreter = this;
lldb::DebuggerSP debugger_sp = m_interpreter.GetDebugger().GetSP();
FILE *tmp_fh = (python_interpreter->m_dbg_stdout ? python_interpreter->m_dbg_stdout : stdout);
{
Locker py_lock(python_interpreter, tmp_fh);
Locker py_lock(this);
FileSpec target_file(pathname, true);
@ -1877,7 +1777,7 @@ ScriptInterpreterPython::LoadScriptingModule (const char* pathname,
command_stream.Printf("if not (sys.path.__contains__('%s')):\n sys.path.append('%s');\n\n",
directory,
directory);
bool syspath_retval = python_interpreter->ExecuteMultipleLines(command_stream.GetData());
bool syspath_retval = ExecuteMultipleLines(command_stream.GetData());
if (!syspath_retval)
{
error.SetErrorString("Python sys.path handling failed");
@ -1897,7 +1797,7 @@ ScriptInterpreterPython::LoadScriptingModule (const char* pathname,
int refcount = 0;
// this call will fail if the module does not exist (because the parameter to it is not a string
// but an actual Python module object, which is non-existant if the module was not imported before)
if (python_interpreter->ExecuteOneLineWithReturn(command_stream.GetData(),
if (ExecuteOneLineWithReturn(command_stream.GetData(),
ScriptInterpreterPython::eScriptReturnTypeInt, &refcount) && refcount > 0)
{
error.SetErrorString("module already imported");
@ -1907,7 +1807,7 @@ ScriptInterpreterPython::LoadScriptingModule (const char* pathname,
// now actually do the import
command_stream.Clear();
command_stream.Printf("import %s",basename.c_str());
bool import_retval = python_interpreter->ExecuteOneLine(command_stream.GetData(), NULL);
bool import_retval = ExecuteOneLine(command_stream.GetData(), NULL);
if (!import_retval)
{
error.SetErrorString("Python import statement failed");
@ -1916,7 +1816,7 @@ ScriptInterpreterPython::LoadScriptingModule (const char* pathname,
// call __lldb_module_init(debugger,dict)
if (!g_swig_call_module_init (basename,
python_interpreter->m_dictionary_name.c_str(),
m_dictionary_name.c_str(),
debugger_sp))
{
error.SetErrorString("calling __lldb_module_init failed");
@ -1944,20 +1844,16 @@ ScriptInterpreterPython::RunScriptBasedCommand(const char* impl_function,
return false;
}
ScriptInterpreterPython *python_interpreter = this;
lldb::DebuggerSP debugger_sp = m_interpreter.GetDebugger().GetSP();
bool ret_val;
std::string err_msg;
FILE *tmp_fh = (python_interpreter->m_dbg_stdout ? python_interpreter->m_dbg_stdout : stdout);
{
Locker py_lock(python_interpreter, tmp_fh);
Locker py_lock(this);
ret_val = g_swig_call_command (impl_function,
python_interpreter->m_dictionary_name.c_str(),
m_dictionary_name.c_str(),
debugger_sp,
args,
err_msg,