[Lldb-commits] [lldb] r162161 - in /lldb/trunk: ./ include/lldb/Interpreter/ScriptInterpreterPython.h scripts/Python/build-swig-Python.sh source/Expression/ClangUserExpression.cpp source/Interpreter/ScriptInterpreterPython.cpp

Johnny Chen johnny.chen at apple.com
Mon Aug 20 10:02:26 PDT 2012


Hi Filipe,

Thank you for contributing to the python GIL work, among other things, of course. :-)

On Aug 20, 2012, at 3:42 AM, Filipe Cabecinhas <filcab at gmail.com> wrote:

> Thanks! 
> 
> I will be contributing some more Python stuff this week, now that we have GIL support :)
> 
> Regards, 
> 
>  Filipe
> 
> 
> On Saturday, August 18, 2012 at 5:14 AM, Johnny Chen wrote:
> 
>> Author: johnny
>> Date: Fri Aug 17 23:14:54 2012
>> New Revision: 162161
>> 
>> URL: http://llvm.org/viewvc/llvm-project?rev=162161&view=rev
>> Log:
>> Merge python-GIL bracnh (by filcab) back into trunk!
>> 
>> Modified:
>> lldb/trunk/ (props changed)
>> lldb/trunk/include/lldb/Interpreter/ScriptInterpreterPython.h
>> lldb/trunk/scripts/Python/build-swig-Python.sh (http://build-swig-Python.sh)
>> lldb/trunk/source/Expression/ClangUserExpression.cpp
>> lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp
>> 
>> Propchange: lldb/trunk/
>> ------------------------------------------------------------------------------
>> svn:mergeinfo = /lldb/branches/apple/python-GIL:156467-162159
>> 
>> Modified: lldb/trunk/include/lldb/Interpreter/ScriptInterpreterPython.h
>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Interpreter/ScriptInterpreterPython.h?rev=162161&r1=162160&r2=162161&view=diff
>> ==============================================================================
>> --- lldb/trunk/include/lldb/Interpreter/ScriptInterpreterPython.h (original)
>> +++ lldb/trunk/include/lldb/Interpreter/ScriptInterpreterPython.h Fri Aug 17 23:14:54 2012
>> @@ -253,10 +253,7 @@
>> FILE* wait_msg_handle = NULL);
>> 
>> ~Locker ();
>> - 
>> - static bool
>> - CurrentThreadHasPythonLock ();
>> - 
>> +
>> private:
>> 
>> bool
>> @@ -270,17 +267,14 @@
>> 
>> 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;
>> FILE* m_tmp_fh;
>> + PyGILState_STATE m_GILState;
>> };
>> 
>> class PythonInputReaderManager
>> @@ -335,7 +329,6 @@
>> bool m_session_is_active;
>> bool m_pty_slave_is_open;
>> bool m_valid_session;
>> - 
>> };
>> } // namespace lldb_private
>> 
>> 
>> Modified: lldb/trunk/scripts/Python/build-swig-Python.sh (http://build-swig-Python.sh)
>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/scripts/Python/build-swig-Python.sh?rev=162161&r1=162160&r2=162161&view=diff
>> ==============================================================================
>> --- lldb/trunk/scripts/Python/build-swig-Python.sh (http://build-swig-Python.sh) (original)
>> +++ lldb/trunk/scripts/Python/build-swig-Python.sh (http://build-swig-Python.sh) Fri Aug 17 23:14:54 2012
>> @@ -289,7 +289,7 @@
>> 
>> # Build the SWIG C++ wrapper file for Python.
>> 
>> -$SWIG -c++ -shadow -python -I"/usr/include" -I"${SRC_ROOT}/include" -I./. -outdir "${CONFIG_BUILD_DIR}" -o "${swig_output_file}" "${swig_input_file}"
>> +$SWIG -c++ -shadow -python -threads -I"/usr/include" -I"${SRC_ROOT}/include" -I./. -outdir "${CONFIG_BUILD_DIR}" -o "${swig_output_file}" "${swig_input_file}"
>> 
>> # Implement the iterator protocol and/or eq/ne operators for some lldb objects.
>> # Append global variable to lldb Python module.
>> 
>> Modified: lldb/trunk/source/Expression/ClangUserExpression.cpp
>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/ClangUserExpression.cpp?rev=162161&r1=162160&r2=162161&view=diff
>> ==============================================================================
>> --- lldb/trunk/source/Expression/ClangUserExpression.cpp (original)
>> +++ lldb/trunk/source/Expression/ClangUserExpression.cpp Fri Aug 17 23:14:54 2012
>> @@ -556,8 +556,10 @@
>> lldb::addr_t object_ptr = 0;
>> lldb::addr_t cmd_ptr = 0;
>> 
>> - if (!PrepareToExecuteJITExpression (error_stream, exe_ctx, struct_address, object_ptr, cmd_ptr))
>> + if (!PrepareToExecuteJITExpression (error_stream, exe_ctx, struct_address, object_ptr, cmd_ptr)) {
>> + error_stream.Printf("Errored out in %s, couldn't PrepareToExecuteJITExpression", __FUNCTION__);
>> return eExecutionSetupError;
>> + }
>> 
>> const bool stop_others = true;
>> const bool try_all_threads = true;
>> @@ -630,6 +632,7 @@
>> if (FinalizeJITExecution (error_stream, exe_ctx, result, function_stack_pointer))
>> return eExecutionCompleted;
>> else
>> + error_stream.Printf("Errored out in %s: Couldn't FinalizeJITExpression", __FUNCTION__);
>> return eExecutionSetupError;
>> }
>> else
>> 
>> Modified: lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp
>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp?rev=162161&r1=162160&r2=162161&view=diff
>> ==============================================================================
>> --- lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp (original)
>> +++ lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp Fri Aug 17 23:14:54 2012
>> @@ -128,73 +128,18 @@
>> return fflush (stream) || prev_fail ? EOF : 0;
>> }
>> 
>> -static Predicate<lldb::tid_t> &
>> -PythonMutexPredicate ()
>> -{
>> - static lldb_private::Predicate<lldb::tid_t> g_interpreter_is_running (LLDB_INVALID_THREAD_ID);
>> - return g_interpreter_is_running;
>> -}
>> -
>> -bool
>> -ScriptInterpreterPython::Locker::CurrentThreadHasPythonLock ()
>> -{
>> - TimeValue timeout;
>> -
>> - timeout = TimeValue::Now(); // Don't wait any time.
>> -
>> - return PythonMutexPredicate().WaitForValueEqualTo (Host::GetCurrentThreadID(), &timeout, NULL);
>> -}
>> -
>> -bool
>> -ScriptInterpreterPython::Locker::TryGetPythonLock (uint32_t seconds_to_wait)
>> -{
>> - 
>> - TimeValue timeout;
>> - 
>> - if (seconds_to_wait != UINT32_MAX)
>> - {
>> - timeout = TimeValue::Now();
>> - timeout.OffsetWithSeconds (seconds_to_wait);
>> - }
>> - 
>> - return PythonMutexPredicate().WaitForValueEqualToAndSetValueTo (LLDB_INVALID_THREAD_ID, 
>> - Host::GetCurrentThreadID(), &timeout, NULL);
>> -}
>> -
>> -void
>> -ScriptInterpreterPython::Locker::ReleasePythonLock ()
>> -{
>> - PythonMutexPredicate().SetValue (LLDB_INVALID_THREAD_ID, eBroadcastAlways);
>> -}
>> -
>> 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 (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 )
>> - {
>> - if (CurrentThreadHasPythonLock())
>> - {
>> - if ( (on_leave & FreeLock) == FreeLock )
>> - m_release_lock = true;
>> - }
>> - else
>> - {
>> - DoAcquireLock();
>> - if ( (on_leave & FreeLock) == FreeLock )
>> - m_release_lock = true;
>> - if ( (on_leave & FreeAcquiredLock) == FreeAcquiredLock )
>> - m_release_lock = true;
>> - }
>> - }
>> +
>> + DoAcquireLock();
>> if ( (on_entry & InitSession) == InitSession )
>> DoInitSession();
>> }
>> @@ -202,13 +147,10 @@
>> 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");
>> - }
>> + LogSP log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT | LIBLLDB_LOG_VERBOSE));
>> + m_GILState = PyGILState_Ensure();
>> + if (log)
>> + log->Printf("Ensured PyGILState. Previous state = %slocked\n", m_GILState == PyGILState_UNLOCKED ? "un" : "");
>> return true;
>> }
>> 
>> @@ -224,7 +166,10 @@
>> bool
>> ScriptInterpreterPython::Locker::DoFreeLock()
>> {
>> - ReleasePythonLock ();
>> + LogSP log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT | LIBLLDB_LOG_VERBOSE));
>> + if (log)
>> + log->Printf("Releasing PyGILState. Returning to state = %slocked\n", m_GILState == PyGILState_UNLOCKED ? "un" : "");
>> + PyGILState_Release(m_GILState);
>> return true;
>> }
>> 
>> @@ -241,8 +186,7 @@
>> {
>> if (m_need_session)
>> DoTearDownSession();
>> - if (m_release_lock)
>> - DoFreeLock();
>> + DoFreeLock();
>> }
>> 
>> class ForceDisableSyntheticChildren
>> @@ -357,13 +301,7 @@
>> input_fd = STDIN_FILENO;
>> 
>> script_interpreter->SaveTerminalState(input_fd);
>> - 
>> - {
>> - ScriptInterpreterPython::Locker locker(script_interpreter,
>> - ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession,
>> - ScriptInterpreterPython::Locker::FreeAcquiredLock);
>> - }
>> - 
>> +
>> char error_str[1024];
>> if (script_interpreter->m_embedded_thread_pty.OpenFirstAvailableMaster (O_RDWR|O_NOCTTY, error_str, 
>> sizeof(error_str)))
>> @@ -377,6 +315,9 @@
>> const char *pty_slave_name = script_interpreter->m_embedded_thread_pty.GetSlaveName (error_str, sizeof (error_str));
>> if (pty_slave_name != NULL && PyThreadState_GetDict() != NULL)
>> {
>> + ScriptInterpreterPython::Locker locker(script_interpreter,
>> + ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession,
>> + ScriptInterpreterPython::Locker::FreeAcquiredLock);
>> 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 ();
>> @@ -428,20 +369,9 @@
>> 
>> case eInputReaderReactivate:
>> {
>> - // Don't try and acquire the interpreter lock here because code like
>> - // this:
>> - //
>> - // (lldb) script
>> - // >>> v = lldb.frame.EvaluateExpression("collection->get_at_index(12)")
>> - //
>> - // This will cause the process to run. The interpreter lock is taken
>> - // by the input reader for the "script" command. If we try and acquire
>> - // the lock here, when the process runs it might deactivate this input
>> - // reader (if STDIN is hooked up to the inferior process) and 
>> - // reactivate it when the process stops which will deadlock.
>> - //ScriptInterpreterPython::Locker locker(script_interpreter,
>> - // ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession,
>> - // ScriptInterpreterPython::Locker::FreeAcquiredLock);
>> + ScriptInterpreterPython::Locker locker(script_interpreter,
>> + ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession,
>> + ScriptInterpreterPython::Locker::FreeAcquiredLock);
>> }
>> break;
>> 
>> @@ -484,6 +414,9 @@
>> const char *pty_slave_name = script_interpreter->m_embedded_thread_pty.GetSlaveName (error_str, sizeof (error_str));
>> if (pty_slave_name != NULL && PyThreadState_GetDict() != NULL)
>> {
>> + ScriptInterpreterPython::Locker locker(script_interpreter,
>> + ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession,
>> + ScriptInterpreterPython::Locker::FreeAcquiredLock);
>> run_string.Printf ("run_one_line (%s, 'sys.stdin = save_stdin')", script_interpreter->m_dictionary_name.c_str());
>> PyRun_SimpleString (run_string.GetData());
>> run_string.Clear();
>> @@ -531,14 +464,14 @@
>> g_initialized = true;
>> ScriptInterpreterPython::InitializePrivate ();
>> }
>> - 
>> - Locker locker(this,
>> - ScriptInterpreterPython::Locker::AcquireLock,
>> - ScriptInterpreterPython::Locker::FreeAcquiredLock);
>> 
>> m_dictionary_name.append("_dict");
>> StreamString run_string;
>> run_string.Printf ("%s = dict()", m_dictionary_name.c_str());
>> +
>> + Locker locker(this,
>> + ScriptInterpreterPython::Locker::AcquireLock,
>> + ScriptInterpreterPython::Locker::FreeAcquiredLock);
>> PyRun_SimpleString (run_string.GetData());
>> 
>> run_string.Clear();
>> @@ -957,20 +890,9 @@
>> 
>> case eInputReaderReactivate:
>> {
>> - // Don't try and acquire the interpreter lock here because code like
>> - // this:
>> - //
>> - // (lldb) script
>> - // >>> v = lldb.frame.EvaluateExpression("collection->get_at_index(12)")
>> - //
>> - // This will cause the process to run. The interpreter lock is taken
>> - // by the input reader for the "script" command. If we try and acquire
>> - // the lock here, when the process runs it might deactivate this input
>> - // reader (if STDIN is hooked up to the inferior process) and 
>> - // reactivate it when the process stops which will deadlock.
>> - //ScriptInterpreterPython::Locker locker(script_interpreter,
>> - // ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession,
>> - // ScriptInterpreterPython::Locker::FreeAcquiredLock);
>> + ScriptInterpreterPython::Locker locker(script_interpreter,
>> + ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession,
>> + ScriptInterpreterPython::Locker::FreeAcquiredLock);
>> }
>> break;
>> 
>> @@ -1012,7 +934,12 @@
>> break;
>> 
>> case eInputReaderDone:
>> - script_interpreter->LeaveSession ();
>> + {
>> + Locker locker(script_interpreter,
>> + ScriptInterpreterPython::Locker::AcquireLock,
>> + ScriptInterpreterPython::Locker::FreeAcquiredLock);
>> + script_interpreter->LeaveSession ();
>> + }
>> 
>> // Restore terminal settings if they were validly saved
>> if (log)
>> @@ -2033,14 +1960,18 @@
>> char error_str[1024];
>> const char *pty_slave_name = script_interpreter->m_embedded_python_pty.GetSlaveName (error_str, sizeof (error_str));
>> 
>> - Locker locker(script_interpreter,
>> - ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession,
>> - ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession);
>> -
>> if (pty_slave_name != NULL)
>> {
>> StreamString run_string;
>> - 
>> +
>> + // Ensure we have the GIL before running any Python code.
>> + // Since we're only running a few one-liners and then dropping to the interpreter (which will release the GIL when needed),
>> + // we can just release the GIL after finishing our work.
>> + // If finer-grained locking is desirable, we can lock and unlock the GIL only when calling a python function.
>> + Locker locker(script_interpreter,
>> + ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession,
>> + ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession);
>> +
>> 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 ();
>> @@ -2060,36 +1991,25 @@
>> 
>> // The following call drops into the embedded interpreter loop and stays there until the
>> // user chooses to exit from the Python interpreter.
>> + // This embedded interpreter will, as any Python code that performs I/O, unlock the GIL before
>> + // a system call that can hang, and lock it when the syscall has returned.
>> 
>> - // When in the embedded interpreter, the user can call arbitrary system and Python stuff, which may require
>> - // the ability to run multi-threaded stuff, so we need to surround the call to the embedded interpreter with
>> - // calls to Py_BEGIN_ALLOW_THREADS and Py_END_ALLOW_THREADS.
>> -
>> - // We ALSO need to surround the call to the embedded interpreter with calls to PyGILState_Ensure and 
>> - // PyGILState_Release. This is because this embedded interpreter is being run on a DIFFERENT THREAD than
>> - // the thread on which the call to Py_Initialize (and PyEval_InitThreads) was called. Those initializations 
>> - // called PyGILState_Ensure on *that* thread, but it also needs to be called on *this* thread. Otherwise,
>> - // if the user calls Python code that does threading stuff, the interpreter state will be off, and things could
>> - // hang (it's happened before).
>> + // We need to surround the call to the embedded interpreter with calls to PyGILState_Ensure and 
>> + // PyGILState_Release (using the Locker above). This is because Python has a global lock which must be held whenever we want
>> + // to touch any Python objects. Otherwise, if the user calls Python code, the interpreter state will be off,
>> + // and things could hang (it's happened before).
>> 
>> - Py_BEGIN_ALLOW_THREADS
>> - PyGILState_STATE gstate = PyGILState_Ensure();
>> - 
>> run_string.Printf ("run_python_interpreter (%s)", script_interpreter->m_dictionary_name.c_str());
>> PyRun_SimpleString (run_string.GetData());
>> run_string.Clear ();
>> - 
>> - PyGILState_Release (gstate);
>> - Py_END_ALLOW_THREADS
>> - 
>> +
>> run_string.Printf ("run_one_line (%s, 'sys.stdin = save_stdin')", script_interpreter->m_dictionary_name.c_str());
>> PyRun_SimpleString (run_string.GetData());
>> run_string.Clear();
>> - 
>> +
>> run_string.Printf ("run_one_line (%s, 'sys.stderr = save_stderr')", script_interpreter->m_dictionary_name.c_str());
>> PyRun_SimpleString (run_string.GetData());
>> run_string.Clear();
>> - 
>> }
>> 
>> if (script_interpreter->m_embedded_python_input_reader_sp)
>> @@ -2261,8 +2181,6 @@
>> lldb::DebuggerSP debugger_sp = m_interpreter.GetDebugger().shared_from_this();
>> 
>> {
>> - Locker py_lock(this);
>> - 
>> FileSpec target_file(pathname, true);
>> 
>> // TODO: would we want to reject any other value?
>> @@ -2275,6 +2193,9 @@
>> 
>> const char* directory = target_file.GetDirectory().GetCString();
>> std::string basename(target_file.GetFilename().GetCString());
>> +
>> + // Before executing Pyton code, lock the GIL.
>> + Locker py_lock(this);
>> 
>> // now make sure that Python has "directory" in the search path
>> StreamString command_stream;
>> @@ -2457,7 +2378,18 @@
>> TerminalState stdin_tty_state;
>> stdin_tty_state.Save(STDIN_FILENO, false);
>> 
>> - PyEval_InitThreads ();
>> + PyGILState_STATE gstate;
>> + LogSP log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT | LIBLLDB_LOG_VERBOSE));
>> + bool threads_already_initialized = false;
>> + if (PyEval_ThreadsInitialized ()) {
>> + gstate = PyGILState_Ensure ();
>> + if (log)
>> + log->Printf("Ensured PyGILState. Previous state = %slocked\n", gstate == PyGILState_UNLOCKED ? "un" : "");
>> + threads_already_initialized = true;
>> + } else {
>> + // InitThreads acquires the GIL if it hasn't been called before.
>> + PyEval_InitThreads ();
>> + }
>> Py_InitializeEx (0);
>> 
>> // Initialize SWIG after setting up python
>> @@ -2500,6 +2432,15 @@
>> 
>> PyRun_SimpleString ("sys.dont_write_bytecode = 1; import lldb.embedded_interpreter; from lldb.embedded_interpreter import run_python_interpreter; from lldb.embedded_interpreter import run_one_line; from termios import *");
>> 
>> + if (threads_already_initialized) {
>> + if (log)
>> + log->Printf("Releasing PyGILState. Returning to state = %slocked\n", gstate == PyGILState_UNLOCKED ? "un" : "");
>> + PyGILState_Release (gstate);
>> + } else {
>> + // We initialized the threads in this function, just unlock the GIL.
>> + PyEval_SaveThread();
>> + }
>> +
>> stdin_tty_state.Restore();
>> }
>> 
>> 
>> 
>> _______________________________________________
>> lldb-commits mailing list
>> lldb-commits at cs.uiuc.edu (mailto:lldb-commits at cs.uiuc.edu)
>> http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits
> 
> 
> 




More information about the lldb-commits mailing list