[Lldb-commits] [lldb] r123674 - in /lldb/trunk/source: Core/Debugger.cpp Interpreter/ScriptInterpreterPython.cpp

Caroline Tice ctice at apple.com
Mon Jan 17 13:55:19 PST 2011


Author: ctice
Date: Mon Jan 17 15:55:19 2011
New Revision: 123674

URL: http://llvm.org/viewvc/llvm-project?rev=123674&view=rev
Log:
Replace Mutex guarding python interpreter access with Predicate,
allowing timeouts & informing the user when the lock is unavailable.


Fixed problem where Debugger::Terminate was clearing the debugger list
even when the global ref count was greater than zero.

Modified:
    lldb/trunk/source/Core/Debugger.cpp
    lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp

Modified: lldb/trunk/source/Core/Debugger.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/Debugger.cpp?rev=123674&r1=123673&r2=123674&view=diff
==============================================================================
--- lldb/trunk/source/Core/Debugger.cpp (original)
+++ lldb/trunk/source/Core/Debugger.cpp Mon Jan 17 15:55:19 2011
@@ -94,11 +94,12 @@
             UserSettingsControllerSP &usc = GetSettingsController();
             UserSettingsController::FinalizeSettingsController (usc);
             usc.reset();
+
+            // Clear our master list of debugger objects
+            Mutex::Locker locker (GetDebuggerListMutex ());
+            GetDebuggerList().clear();
         }
     }
-    // Clear our master list of debugger objects
-    Mutex::Locker locker (GetDebuggerListMutex ());
-    GetDebuggerList().clear();
 }
 
 DebuggerSP

Modified: lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp?rev=123674&r1=123673&r2=123674&view=diff
==============================================================================
--- lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp (original)
+++ lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp Mon Jan 17 15:55:19 2011
@@ -171,11 +171,43 @@
   return fflush (stream) || prev_fail ? EOF : 0;
 }
 
-static Mutex &
-GetPythonMutex ()
+static Predicate<lldb::tid_t> &
+PythonMutexPredicate ()
 {
-    static Mutex g_python_mutex (Mutex::eMutexTypeRecursive);
-    return g_python_mutex;
+    static lldb_private::Predicate<lldb::tid_t> g_interpreter_is_running (LLDB_INVALID_THREAD_ID);
+    return g_interpreter_is_running;
+}
+
+static bool
+CurrentThreadHasPythonLock ()
+{
+    TimeValue timeout;
+
+    timeout = TimeValue::Now();  // Don't wait any time.
+
+    return PythonMutexPredicate().WaitForValueEqualTo (Host::GetCurrentThreadID(), &timeout, NULL);
+}
+
+static bool
+GetPythonLock (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);
+}
+
+static void
+ReleasePythonLock ()
+{
+    PythonMutexPredicate().SetValue (LLDB_INVALID_THREAD_ID, eBroadcastAlways);
 }
 
 ScriptInterpreterPython::ScriptInterpreterPython (CommandInterpreter &interpreter) :
@@ -191,8 +223,33 @@
     m_pty_slave_is_open (false),
     m_valid_session (true)
 {
-    Mutex::Locker locker (GetPythonMutex());
 
+    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;
+        }
+    }
+    
     m_dictionary_name.append("_dict");
     StreamString run_string;
     run_string.Printf ("%s = dict()", m_dictionary_name.c_str());
@@ -234,6 +291,9 @@
     {
         m_new_sysout = PyFile_FromFile (m_dbg_stdout, (char *) "", (char *) "w", _check_and_flush);
     }
+    
+    if (need_to_release_lock)
+        ReleasePythonLock();
 }
 
 ScriptInterpreterPython::~ScriptInterpreterPython ()
@@ -252,8 +312,16 @@
     
     if (m_new_sysout)
     {
-        Mutex::Locker locker(GetPythonMutex());
-        Py_DECREF (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 (m_new_sysout);
+            ReleasePythonLock ();
+        }
+        else
+            Py_DECREF (m_new_sysout);
     }
 }
 
@@ -264,11 +332,23 @@
         return;
         
     m_dbg_stdout = fh;
-    Mutex::Locker locker (GetPythonMutex());
 
-    EnterSession ();
-    m_new_sysout = PyFile_FromFile (m_dbg_stdout, (char *) "", (char *) "w", _check_and_flush);
-    LeaveSession ();
+    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");
+        EnterSession ();
+        m_new_sysout = PyFile_FromFile (m_dbg_stdout, (char *) "", (char *) "w", _check_and_flush);
+        LeaveSession ();
+        ReleasePythonLock ();
+    }
+    else
+    {
+        EnterSession ();
+        m_new_sysout = PyFile_FromFile (m_dbg_stdout, (char *) "", (char *) "w", _check_and_flush);
+        LeaveSession ();
+    }
 }
 
 void
@@ -288,7 +368,12 @@
 
     m_session_is_active = true;
 
-    Mutex::Locker locker (GetPythonMutex());
+    StreamString run_string;
+
+    run_string.Printf ("run_one_line (%s, 'lldb.debugger_unique_id = %d')", m_dictionary_name.c_str(),
+                       GetCommandInterpreter().GetDebugger().GetID());
+    PyRun_SimpleString (run_string.GetData());
+    
 
     PyObject *sysmod = PyImport_AddModule ("sys");
     PyObject *sysdict = PyModule_GetDict (sysmod);
@@ -301,9 +386,9 @@
     if (PyErr_Occurred())
         PyErr_Clear ();
         
-    StreamString run_string;
     if (!m_pty_slave_is_open)
     {
+        run_string.Clear();
         run_string.Printf ("run_one_line (%s, \"new_stdin = open('%s', 'r')\")", m_dictionary_name.c_str(),
                            m_pty_slave_name.c_str());
         PyRun_SimpleString (run_string.GetData());
@@ -322,9 +407,7 @@
     if (!m_valid_session)
         return false;
         
-    EnterSession ();
         
-    Mutex::Locker locker (GetPythonMutex());
 
     // 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
@@ -332,6 +415,18 @@
     // method to pass the command string directly down to Python.
 
 
+    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)
@@ -417,6 +512,9 @@
 
         LeaveSession ();
         
+        if (need_to_release_lock)
+            ReleasePythonLock();
+
         if (success)
             return true;
 
@@ -427,6 +525,10 @@
     }
 
     LeaveSession ();
+
+    if (need_to_release_lock)
+        ReleasePythonLock ();
+
     if (result)
         result->AppendError ("empty command passed to python\n");
     return false;
@@ -478,6 +580,18 @@
 
             script_interpreter->m_termios_valid = ::tcgetattr (input_fd, &script_interpreter->m_termios) == 0;
             
+            if (!CurrentThreadHasPythonLock())
+            {
+                while (!GetPythonLock(1)) 
+                {
+                    ::fprintf (out_fh, "Python interpreter locked on another thread; waiting to acquire lock...\n");
+                }
+                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, 
                                                                                     sizeof(error_str)))
@@ -508,8 +622,6 @@
                     log->Printf ("ScriptInterpreterPython::InputReaderCallback, Activate, failed to open master pty ");
                 reader.SetIsDone (true);
             }
-            script_interpreter->EnterSession ();
-
         }
         break;
 
@@ -518,7 +630,17 @@
         break;
 
     case eInputReaderReactivate:
-        script_interpreter->EnterSession ();
+        if (!CurrentThreadHasPythonLock())
+        {
+            while (!GetPythonLock(1))
+            {
+                // Wait until lock is acquired.
+            }
+            script_interpreter->EnterSession ();
+            ReleasePythonLock();
+        }
+        else
+            script_interpreter->EnterSession ();
         break;
         
     case eInputReaderInterrupt:
@@ -618,9 +740,19 @@
                                                    ScriptInterpreter::ReturnType return_type,
                                                    void *ret_value)
 {
-    EnterSession ();
 
-    Mutex::Locker locker (GetPythonMutex());
+    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 ();
 
     PyObject *py_return = NULL;
     PyObject *mainmod = PyImport_AddModule ("__main__");
@@ -786,15 +918,27 @@
     
     LeaveSession ();
 
+    if (need_to_release_lock)
+        ReleasePythonLock();
+
     return ret_success;
 }
 
 bool
 ScriptInterpreterPython::ExecuteMultipleLines (const char *in_string)
 {
-    EnterSession ();
+    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");
+    }
 
-    Mutex::Locker locker (GetPythonMutex());
+    EnterSession ();
 
     bool success = false;
     PyObject *py_return = NULL;
@@ -867,6 +1011,9 @@
 
     LeaveSession ();
 
+    if (need_to_release_lock)
+        ReleasePythonLock();
+
     return success;
 }
 
@@ -1156,12 +1303,28 @@
         
         if (sb_bp_loc.IsValid() || sb_frame.IsValid())
         {
-            python_interpreter->EnterSession ();
-            Mutex::Locker locker (GetPythonMutex());
-            bool ret_val = LLDBSWIGPythonBreakpointCallbackFunction(python_function_name, 
-                                                                    python_interpreter->m_dictionary_name.c_str(),
-                                                                    sb_frame, sb_bp_loc);
-            python_interpreter->LeaveSession ();
+            bool ret_val = true;
+            FILE *tmp_fh = (python_interpreter->m_dbg_stdout ? python_interpreter->m_dbg_stdout : stdout);
+            if (CurrentThreadHasPythonLock())
+            {
+                python_interpreter->EnterSession ();
+                ret_val = LLDBSWIGPythonBreakpointCallbackFunction(python_function_name, 
+                                                                   python_interpreter->m_dictionary_name.c_str(),
+                                                                   sb_frame, sb_bp_loc);
+                python_interpreter->LeaveSession ();
+            }
+            else
+            {
+                while (!GetPythonLock (1))
+                    fprintf (tmp_fh, 
+                             "Python interpreter locked on another thread; waiting to acquire lock...\n");
+                python_interpreter->EnterSession ();
+                ret_val = LLDBSWIGPythonBreakpointCallbackFunction(python_function_name, 
+                                                                   python_interpreter->m_dictionary_name.c_str(),
+                                                                   sb_frame, sb_bp_loc);
+                python_interpreter->LeaveSession ();
+                ReleasePythonLock ();
+            }
             return ret_val;
         }
     }
@@ -1175,8 +1338,6 @@
 {
     ScriptInterpreterPython *script_interpreter = (ScriptInterpreterPython *) baton;
     
-    script_interpreter->EnterSession ();
-    
     LogSP log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT));
     
     if (log)
@@ -1184,12 +1345,31 @@
     
     char error_str[1024];
     const char *pty_slave_name = script_interpreter->m_embedded_python_pty.GetSlaveName (error_str, sizeof (error_str));
-    if (pty_slave_name != NULL)
-    {
-        Mutex::Locker locker (GetPythonMutex());
+    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);
+        }
+    }
+    
+    if (pty_slave_name != NULL && safe_to_run)
+    {
         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 ();
@@ -1221,8 +1401,18 @@
         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();
+
+        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);
     
@@ -1241,8 +1431,6 @@
     script_interpreter->m_embedded_thread_input_reader_sp.reset();
     debugger.PopInputReader (reader_sp);
     
-    script_interpreter->LeaveSession ();
-        
     return NULL;
 }
 





More information about the lldb-commits mailing list