[lldb] Initialize Python exactly once

We got a few crash reports that showed LLDB initializing Python on two
separate threads. Make sure Python is initialized exactly once.

rdar://87287005

Differential revision: https://reviews.llvm.org/D117601
This commit is contained in:
Jonas Devlieghere 2022-01-19 09:16:16 -08:00
parent 85c2bd2a0e
commit eb5c0ea681
3 changed files with 25 additions and 38 deletions

View File

@ -85,8 +85,6 @@ static ScriptInterpreterPythonImpl *GetPythonInterpreter(Debugger &debugger) {
return static_cast<ScriptInterpreterPythonImpl *>(script_interpreter); return static_cast<ScriptInterpreterPythonImpl *>(script_interpreter);
} }
static bool g_initialized = false;
namespace { namespace {
// Initializing Python is not a straightforward process. We cannot control // Initializing Python is not a straightforward process. We cannot control
@ -219,6 +217,28 @@ private:
PyGILState_STATE m_gil_state = PyGILState_UNLOCKED; PyGILState_STATE m_gil_state = PyGILState_UNLOCKED;
bool m_was_already_initialized = false; bool m_was_already_initialized = false;
}; };
#if LLDB_USE_PYTHON_SET_INTERRUPT
/// Saves the current signal handler for the specified signal and restores
/// it at the end of the current scope.
struct RestoreSignalHandlerScope {
/// The signal handler.
struct sigaction m_prev_handler;
int m_signal_code;
RestoreSignalHandlerScope(int signal_code) : m_signal_code(signal_code) {
// Initialize sigaction to their default state.
std::memset(&m_prev_handler, 0, sizeof(m_prev_handler));
// Don't install a new handler, just read back the old one.
struct sigaction *new_handler = nullptr;
int signal_err = ::sigaction(m_signal_code, new_handler, &m_prev_handler);
lldbassert(signal_err == 0 && "sigaction failed to read handler");
}
~RestoreSignalHandlerScope() {
int signal_err = ::sigaction(m_signal_code, &m_prev_handler, nullptr);
lldbassert(signal_err == 0 && "sigaction failed to restore old handler");
}
};
#endif
} // namespace } // namespace
void ScriptInterpreterPython::ComputePythonDirForApple( void ScriptInterpreterPython::ComputePythonDirForApple(
@ -333,12 +353,12 @@ llvm::StringRef ScriptInterpreterPython::GetPluginDescriptionStatic() {
void ScriptInterpreterPython::Initialize() { void ScriptInterpreterPython::Initialize() {
static llvm::once_flag g_once_flag; static llvm::once_flag g_once_flag;
llvm::call_once(g_once_flag, []() { llvm::call_once(g_once_flag, []() {
PluginManager::RegisterPlugin(GetPluginNameStatic(), PluginManager::RegisterPlugin(GetPluginNameStatic(),
GetPluginDescriptionStatic(), GetPluginDescriptionStatic(),
lldb::eScriptLanguagePython, lldb::eScriptLanguagePython,
ScriptInterpreterPythonImpl::CreateInstance); ScriptInterpreterPythonImpl::CreateInstance);
ScriptInterpreterPythonImpl::Initialize();
}); });
} }
@ -415,8 +435,6 @@ ScriptInterpreterPythonImpl::ScriptInterpreterPythonImpl(Debugger &debugger)
m_active_io_handler(eIOHandlerNone), m_session_is_active(false), m_active_io_handler(eIOHandlerNone), m_session_is_active(false),
m_pty_secondary_is_open(false), m_valid_session(true), m_lock_count(0), m_pty_secondary_is_open(false), m_valid_session(true), m_lock_count(0),
m_command_thread_state(nullptr) { m_command_thread_state(nullptr) {
InitializePrivate();
m_scripted_process_interface_up = m_scripted_process_interface_up =
std::make_unique<ScriptedProcessPythonInterface>(*this); std::make_unique<ScriptedProcessPythonInterface>(*this);
@ -3151,36 +3169,7 @@ ScriptInterpreterPythonImpl::AcquireInterpreterLock() {
return py_lock; return py_lock;
} }
#if LLDB_USE_PYTHON_SET_INTERRUPT void ScriptInterpreterPythonImpl::Initialize() {
namespace {
/// Saves the current signal handler for the specified signal and restores
/// it at the end of the current scope.
struct RestoreSignalHandlerScope {
/// The signal handler.
struct sigaction m_prev_handler;
int m_signal_code;
RestoreSignalHandlerScope(int signal_code) : m_signal_code(signal_code) {
// Initialize sigaction to their default state.
std::memset(&m_prev_handler, 0, sizeof(m_prev_handler));
// Don't install a new handler, just read back the old one.
struct sigaction *new_handler = nullptr;
int signal_err = ::sigaction(m_signal_code, new_handler, &m_prev_handler);
lldbassert(signal_err == 0 && "sigaction failed to read handler");
}
~RestoreSignalHandlerScope() {
int signal_err = ::sigaction(m_signal_code, &m_prev_handler, nullptr);
lldbassert(signal_err == 0 && "sigaction failed to restore old handler");
}
};
} // namespace
#endif
void ScriptInterpreterPythonImpl::InitializePrivate() {
if (g_initialized)
return;
g_initialized = true;
LLDB_SCOPED_TIMER(); LLDB_SCOPED_TIMER();
// RAII-based initialization which correctly handles multiple-initialization, // RAII-based initialization which correctly handles multiple-initialization,

View File

@ -341,7 +341,7 @@ public:
static bool WatchpointCallbackFunction(void *baton, static bool WatchpointCallbackFunction(void *baton,
StoppointCallbackContext *context, StoppointCallbackContext *context,
lldb::user_id_t watch_id); lldb::user_id_t watch_id);
static void InitializePrivate(); static void Initialize();
class SynchronicityHandler { class SynchronicityHandler {
private: private:

View File

@ -22,7 +22,6 @@ using namespace lldb_private;
class TestScriptInterpreterPython : public ScriptInterpreterPythonImpl { class TestScriptInterpreterPython : public ScriptInterpreterPythonImpl {
public: public:
using ScriptInterpreterPythonImpl::Initialize; using ScriptInterpreterPythonImpl::Initialize;
using ScriptInterpreterPythonImpl::InitializePrivate;
}; };
void PythonTestSuite::SetUp() { void PythonTestSuite::SetUp() {
@ -31,7 +30,6 @@ void PythonTestSuite::SetUp() {
// ScriptInterpreterPython::Initialize() depends on HostInfo being // ScriptInterpreterPython::Initialize() depends on HostInfo being
// initializedso it can compute the python directory etc. // initializedso it can compute the python directory etc.
TestScriptInterpreterPython::Initialize(); TestScriptInterpreterPython::Initialize();
TestScriptInterpreterPython::InitializePrivate();
// Although we don't care about concurrency for the purposes of running // Although we don't care about concurrency for the purposes of running
// this test suite, Python requires the GIL to be locked even for // this test suite, Python requires the GIL to be locked even for