summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/ScriptInterpreter/Python
diff options
context:
space:
mode:
authorZachary Turner <zturner@google.com>2015-10-14 17:51:29 +0000
committerZachary Turner <zturner@google.com>2015-10-14 17:51:29 +0000
commit079fe48a1d693078c756ec114bb84e194f514390 (patch)
tree81610b026d1f636d6e7e977815bdcdadf39c54f2 /lldb/source/Plugins/ScriptInterpreter/Python
parent4bca0bb010ffa7a48951fca6d06a2b4a931cde8d (diff)
downloadbcm5719-llvm-079fe48a1d693078c756ec114bb84e194f514390.tar.gz
bcm5719-llvm-079fe48a1d693078c756ec114bb84e194f514390.zip
Fix Python initialization for Python 3.
Python 3 reverses the order in which you must call Py_InitializeEx and PyEval_InitThreads. Since that log is in itself already a little nuanced, it is refactored into a function so that the reversal is more clear. At the same time, there's a lot of logic during Python initialization to save off a bunch of state and then restore it after initialization is complete. To express this more cleanly, it is refactored to an RAII-style pattern where state is saved off on acquisition and restored on release. llvm-svn: 250306
Diffstat (limited to 'lldb/source/Plugins/ScriptInterpreter/Python')
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp137
1 files changed, 91 insertions, 46 deletions
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
index 83334e9c1a9..9dda825803f 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
@@ -80,27 +80,101 @@ static ScriptInterpreterPython::SWIGPythonCallThreadPlan g_swig_call_thread_plan
static bool g_initialized = false;
-#if PY_MAJOR_VERSION >= 3 && defined(LLDB_PYTHON_HOME)
-typedef wchar_t PythonHomeChar;
+namespace
+{
+
+// Initializing Python is not a straightforward process. We cannot control what
+// external code may have done before getting to this point in LLDB, including
+// potentially having already initialized Python, so we need to do a lot of work
+// to ensure that the existing state of the system is maintained across our
+// initialization. We do this by using an RAII pattern where we save off initial
+// state at the beginning, and restore it at the end
+struct InitializePythonRAII
+{
+public:
+ InitializePythonRAII() :
+ m_was_already_initialized(false),
+ m_gil_state(PyGILState_UNLOCKED)
+ {
+ // Python will muck with STDIN terminal state, so save off any current TTY
+ // settings so we can restore them.
+ m_stdin_tty_state.Save(STDIN_FILENO, false);
+
+ InitializePythonHome();
+
+ // Python < 3.2 and Python >= 3.2 reversed the ordering requirements for
+ // calling `Py_Initialize` and `PyEval_InitThreads`. < 3.2 requires that you
+ // call `PyEval_InitThreads` first, and >= 3.2 requires that you call it last.
+#if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 2) || (PY_MAJOR_VERSION > 3)
+ Py_InitializeEx(0);
+ InitializeThreadsPrivate();
#else
-typedef char PythonHomeChar;
+ InitializeThreadsPrivate();
+ Py_InitializeEx(0);
#endif
+ }
-PythonHomeChar *
-GetDesiredPythonHome()
-{
+ ~InitializePythonRAII()
+ {
+ if (m_was_already_initialized)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SCRIPT | LIBLLDB_LOG_VERBOSE));
+
+ if (log)
+ {
+ log->Printf("Releasing PyGILState. Returning to state = %slocked\n",
+ m_was_already_initialized == PyGILState_UNLOCKED ? "un" : "");
+ }
+ PyGILState_Release(m_gil_state);
+ }
+ else
+ {
+ // We initialized the threads in this function, just unlock the GIL.
+ PyEval_SaveThread();
+ }
+
+ m_stdin_tty_state.Restore();
+ }
+
+private:
+ void InitializePythonHome()
+ {
#if defined(LLDB_PYTHON_HOME)
#if PY_MAJOR_VERSION >= 3
- size_t size = 0;
- static PythonHomeChar *g_python_home = Py_DecodeLocale(LLDB_PYTHON_HOME, &size);
- return g_python_home;
+ size_t size = 0;
+ static wchar_t *g_python_home = Py_DecodeLocale(LLDB_PYTHON_HOME, &size);
#else
- static PythonHomeChar *g_python_home = LLDB_PYTHON_HOME;
- return g_python_home;
+ static char *g_python_home = LLDB_PYTHON_HOME;
#endif
-#else
- return nullptr;
+ Py_SetPythonHome(g_python_home);
#endif
+ }
+
+ void InitializeThreadsPrivate()
+ {
+ if (PyEval_ThreadsInitialized())
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SCRIPT | LIBLLDB_LOG_VERBOSE));
+
+ m_was_already_initialized = true;
+ m_gil_state = PyGILState_Ensure();
+ if (log)
+ {
+ log->Printf("Ensured PyGILState. Previous state = %slocked\n",
+ m_gil_state == PyGILState_UNLOCKED ? "un" : "");
+ }
+ return;
+ }
+
+ // InitThreads acquires the GIL if it hasn't been called before.
+ PyEval_InitThreads();
+ }
+
+ TerminalState m_stdin_tty_state;
+ PyGILState_STATE m_gil_state;
+ bool m_was_already_initialized;
+};
+
}
static std::string ReadPythonBacktrace(PythonObject py_backtrace);
@@ -3104,28 +3178,10 @@ ScriptInterpreterPython::InitializePrivate ()
Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
- // Python will muck with STDIN terminal state, so save off any current TTY
- // settings so we can restore them.
- TerminalState stdin_tty_state;
- stdin_tty_state.Save(STDIN_FILENO, false);
-
-#if defined(LLDB_PYTHON_HOME)
- Py_SetPythonHome(GetDesiredPythonHome());
-#endif
-
- PyGILState_STATE gstate;
- Log *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);
+ // RAII-based initialization which correctly handles multiple-initialization, version-
+ // specific differences among Python 2 and Python 3, and saving and restoring various
+ // other pieces of state that can get mucked with during initialization.
+ InitializePythonRAII initialize_guard;
if (g_swig_init_callback)
g_swig_init_callback ();
@@ -3146,17 +3202,6 @@ ScriptInterpreterPython::InitializePrivate ()
AddToSysPath(AddLocation::Beginning, file_spec.GetPath(false));
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");
-
- 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();
}
void
OpenPOWER on IntegriCloud