[Lldb-commits] [lldb] r238313 - Improve LLDB prompt handling

Pavel Labath labath at google.com
Wed May 27 05:40:33 PDT 2015


Author: labath
Date: Wed May 27 07:40:32 2015
New Revision: 238313

URL: http://llvm.org/viewvc/llvm-project?rev=238313&view=rev
Log:
Improve LLDB prompt handling

Summary:
There is an issue in lldb where the command prompt can appear at the wrong time. The partial fix
we have in for this is not working all the time and is introducing unnecessary delays. This
change does:
- Change Process:SyncIOHandler to use integer start id's for synchronization to avoid it being
  confused by quick start-stop cycles. I picked this up from a suggested patch by Greg to
  lldb-dev.
- coordinates printing of asynchronous text with the iohandlers. This is also based on a
  (different) Greg's patch, but I have added stronger synchronization to it to avoid races.

Together, these changes solve the prompt problem for me on linux (both with and without libedit).
I think they should behave similarly on Mac and FreeBSD and I think they will not make matters
worse for windows.

Test Plan: Prompt comes out alright. All tests still pass on linux.

Reviewers: clayborg, emaste, zturner

Subscribers: lldb-commits

Differential Revision: http://reviews.llvm.org/D9823

Modified:
    lldb/trunk/include/lldb/Core/Debugger.h
    lldb/trunk/include/lldb/Core/IOHandler.h
    lldb/trunk/include/lldb/Core/StreamAsynchronousIO.h
    lldb/trunk/include/lldb/Host/Editline.h
    lldb/trunk/include/lldb/Target/Process.h
    lldb/trunk/source/Commands/CommandObjectProcess.cpp
    lldb/trunk/source/Commands/CommandObjectThread.cpp
    lldb/trunk/source/Core/Debugger.cpp
    lldb/trunk/source/Core/IOHandler.cpp
    lldb/trunk/source/Core/StreamAsynchronousIO.cpp
    lldb/trunk/source/Host/common/Editline.cpp
    lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp
    lldb/trunk/source/Target/Process.cpp

Modified: lldb/trunk/include/lldb/Core/Debugger.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/Debugger.h?rev=238313&r1=238312&r2=238313&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/Debugger.h (original)
+++ lldb/trunk/include/lldb/Core/Debugger.h Wed May 27 07:40:32 2015
@@ -210,6 +210,9 @@ public:
     bool
     IsTopIOHandler (const lldb::IOHandlerSP& reader_sp);
 
+    void
+    PrintAsync (const char *s, size_t len, bool is_stdout);
+
     ConstString
     GetTopIOHandlerControlSequence(char ch);
 
@@ -219,12 +222,6 @@ public:
     const char *
     GetIOHandlerHelpPrologue();
 
-    bool
-    HideTopIOHandler();
-
-    void
-    RefreshTopIOHandler();
-
     static lldb::DebuggerSP
     FindDebuggerWithID (lldb::user_id_t id);
     

Modified: lldb/trunk/include/lldb/Core/IOHandler.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/IOHandler.h?rev=238313&r1=238312&r2=238313&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/IOHandler.h (original)
+++ lldb/trunk/include/lldb/Core/IOHandler.h Wed May 27 07:40:32 2015
@@ -67,18 +67,6 @@ namespace lldb_private {
         virtual void
         Run () = 0;
 
-        // Hide any characters that have been displayed so far so async
-        // output can be displayed. Refresh() will be called after the
-        // output has been displayed.
-        virtual void
-        Hide () = 0;
-        
-        // Called when the async output has been received in order to update
-        // the input reader (refresh the prompt and redisplay any current
-        // line(s) that are being edited
-        virtual void
-        Refresh () = 0;
-
         // Called when an input reader should relinquish its control so another
         // can be pushed onto the IO handler stack, or so the current IO
         // handler can pop itself off the stack
@@ -246,7 +234,14 @@ namespace lldb_private {
         
         void
         WaitForPop ();
-        
+
+        virtual void
+        PrintAsync (Stream *stream, const char *s, size_t len)
+        {
+            stream->Write (s, len);
+            stream->Flush();
+        }
+
     protected:
         Debugger &m_debugger;
         lldb::StreamFileSP m_input_sp;
@@ -448,17 +443,17 @@ namespace lldb_private {
         {
         }
         
-        virtual ConstString
-        IOHandlerGetControlSequence (char ch)
+        ConstString
+        IOHandlerGetControlSequence (char ch) override
         {
             if (ch == 'd')
                 return ConstString (m_end_line + "\n");
             return ConstString();
         }
 
-        virtual bool
+        bool
         IOHandlerIsInputComplete (IOHandler &io_handler,
-                                  StringList &lines)
+                                  StringList &lines) override
         {
             // Determine whether the end of input signal has been entered
             const size_t num_lines = lines.GetSize();
@@ -507,53 +502,47 @@ namespace lldb_private {
         virtual
         ~IOHandlerEditline ();
         
-        virtual void
-        Run ();
+        void
+        Run () override;
         
-        virtual void
-        Hide ();
-
-        virtual void
-        Refresh ();
-
-        virtual void
-        Cancel ();
+        void
+        Cancel () override;
 
-        virtual bool
-        Interrupt ();
+        bool
+        Interrupt () override;
         
-        virtual void
-        GotEOF();
+        void
+        GotEOF() override;
         
-        virtual void
-        Activate ();
+        void
+        Activate () override;
 
-        virtual void
-        Deactivate ();
+        void
+        Deactivate () override;
 
-        virtual ConstString
-        GetControlSequence (char ch)
+        ConstString
+        GetControlSequence (char ch) override
         {
             return m_delegate.IOHandlerGetControlSequence (ch);
         }
 
-        virtual const char *
-        GetCommandPrefix ()
+        const char *
+        GetCommandPrefix () override
         {
             return m_delegate.IOHandlerGetCommandPrefix ();
         }
 
-        virtual const char *
-        GetHelpPrologue ()
+        const char *
+        GetHelpPrologue () override
         {
             return m_delegate.IOHandlerGetHelpPrologue ();
         }
 
-        virtual const char *
-        GetPrompt ();
+        const char *
+        GetPrompt () override;
         
-        virtual bool
-        SetPrompt (const char *prompt);
+        bool
+        SetPrompt (const char *prompt) override;
         
         const char *
         GetContinuationPrompt ();
@@ -591,6 +580,9 @@ namespace lldb_private {
         uint32_t
         GetCurrentLineIndex () const;
 
+        void
+        PrintAsync (Stream *stream, const char *s, size_t len) override;
+
     private:
 #ifndef LLDB_DISABLE_LIBEDIT
         static bool
@@ -649,17 +641,17 @@ namespace lldb_private {
             return m_user_response;
         }
         
-        virtual int
+        int
         IOHandlerComplete (IOHandler &io_handler,
                            const char *current_line,
                            const char *cursor,
                            const char *last_char,
                            int skip_first_n_matches,
                            int max_matches,
-                           StringList &matches);
+                           StringList &matches) override;
         
-        virtual void
-        IOHandlerInputComplete (IOHandler &io_handler, std::string &data);
+        void
+        IOHandlerInputComplete (IOHandler &io_handler, std::string &data) override;
 
     protected:
         const bool m_default_response;
@@ -672,32 +664,25 @@ namespace lldb_private {
     public:
         IOHandlerCursesGUI (Debugger &debugger);
         
-        virtual
-        ~IOHandlerCursesGUI ();
-        
-        virtual void
-        Run ();
+        ~IOHandlerCursesGUI () override;
         
-        virtual void
-        Hide ();
+        void
+        Run () override;
         
-        virtual void
-        Refresh ();
-
-        virtual void
-        Cancel ();
+        void
+        Cancel () override;
 
-        virtual bool
-        Interrupt ();
+        bool
+        Interrupt () override;
         
-        virtual void
-        GotEOF();
+        void
+        GotEOF() override;
         
-        virtual void
-        Activate ();
+        void
+        Activate () override;
         
-        virtual void
-        Deactivate ();
+        void
+        Deactivate () override;
 
     protected:
         curses::ApplicationAP m_app_ap;
@@ -712,20 +697,11 @@ namespace lldb_private {
         virtual
         ~IOHandlerCursesValueObjectList ();
         
-        virtual void
-        Run ();
-        
-        virtual void
-        Hide ();
-        
-        virtual void
-        Refresh ();
-        
-        virtual bool
-        HandleInterrupt ();
+        void
+        Run () override;
         
-        virtual void
-        GotEOF();
+        void
+        GotEOF() override;
     protected:
         ValueObjectList m_valobj_list;
     };
@@ -850,7 +826,10 @@ namespace lldb_private {
             return NULL;
         }
 
-    protected:        
+        void
+        PrintAsync (Stream *stream, const char *s, size_t len);
+
+    protected:
         
         typedef std::vector<lldb::IOHandlerSP> collection;
         collection m_stack;

Modified: lldb/trunk/include/lldb/Core/StreamAsynchronousIO.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/StreamAsynchronousIO.h?rev=238313&r1=238312&r2=238313&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/StreamAsynchronousIO.h (original)
+++ lldb/trunk/include/lldb/Core/StreamAsynchronousIO.h Wed May 27 07:40:32 2015
@@ -20,7 +20,7 @@ class StreamAsynchronousIO :
     public Stream
 {
 public:
-    StreamAsynchronousIO (Broadcaster &broadcaster, uint32_t broadcast_event_type);
+    StreamAsynchronousIO (Debugger &debugger, bool for_stdout);
     
     virtual ~StreamAsynchronousIO ();
     
@@ -32,9 +32,9 @@ public:
     
     
 private:
-    Broadcaster &m_broadcaster;
-    uint32_t m_broadcast_event_type;
-    std::string m_accumulated_data;
+    Debugger &m_debugger;
+    std::string m_data;
+    bool m_for_stdout;
 };
 
 } // namespace lldb_private

Modified: lldb/trunk/include/lldb/Host/Editline.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Host/Editline.h?rev=238313&r1=238312&r2=238313&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Host/Editline.h (original)
+++ lldb/trunk/include/lldb/Host/Editline.h Wed May 27 07:40:32 2015
@@ -171,17 +171,13 @@ namespace lldb_private {
         uint32_t
         GetCurrentLine();
 
-        /// Hides the current input session in preparation for output
-        void
-        Hide();
-        
-        /// Prepare to return to editing after a call to Hide()
-        void
-        Refresh();
-
         /// Interrupt the current edit as if ^C was pressed
         bool
         Interrupt();
+
+        /// Cancel this edit and oblitarate all trace of it
+        bool
+        Cancel();
         
         /// Register a callback for the tab key
         void
@@ -207,6 +203,9 @@ namespace lldb_private {
         bool
         GetLines (int first_line_number, StringList &lines, bool &interrupted);
         
+        void
+        PrintAsync (Stream *stream, const char *s, size_t len);
+
     private:
         
         /// Sets the lowest line number for multi-line editing sessions.  A value of zero suppresses
@@ -335,7 +334,6 @@ namespace lldb_private {
         bool m_multiline_enabled = false;
         std::vector<EditLineStringType> m_input_lines;
         EditorStatus m_editor_status;
-        bool m_editor_getting_char = false;
         bool m_color_prompts = true;
         int m_terminal_width = 0;
         int m_base_line_number = 0;
@@ -359,6 +357,8 @@ namespace lldb_private {
         const char * m_fix_indentation_callback_chars = nullptr;
         CompleteCallbackType m_completion_callback = nullptr;
         void * m_completion_callback_baton = nullptr;
+
+        Mutex m_output_mutex;
     };
 }
 

Modified: lldb/trunk/include/lldb/Target/Process.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Process.h?rev=238313&r1=238312&r2=238313&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Process.h (original)
+++ lldb/trunk/include/lldb/Target/Process.h Wed May 27 07:40:32 2015
@@ -2746,6 +2746,11 @@ public:
                           Listener *hijack_listener = NULL,
                           Stream *stream = NULL);
 
+    uint32_t
+    GetIOHandlerID () const
+    {
+        return m_iohandler_sync.GetValue();
+    }
 
     //--------------------------------------------------------------------------------------
     /// Waits for the process state to be running within a given msec timeout.
@@ -2756,14 +2761,9 @@ public:
     /// @param[in] timeout_msec
     ///     The maximum time length to wait for the process to transition to the
     ///     eStateRunning state, specified in milliseconds.
-    ///
-    /// @return
-    ///     true if successfully signalled that process started and IOHandler pushes, false
-    ///     if it timed out.
     //--------------------------------------------------------------------------------------
-    bool
-    SyncIOHandler (uint64_t timeout_msec);
-
+    void
+    SyncIOHandler (uint32_t iohandler_id, uint64_t timeout_msec);
 
     lldb::StateType
     WaitForStateChangedEvents (const TimeValue *timeout,
@@ -3186,7 +3186,7 @@ protected:
     std::string                 m_stderr_data;
     Mutex                       m_profile_data_comm_mutex;
     std::vector<std::string>    m_profile_data;
-    Predicate<bool>             m_iohandler_sync;
+    Predicate<uint32_t>         m_iohandler_sync;
     MemoryCache                 m_memory_cache;
     AllocatedMemoryCache        m_allocated_memory_cache;
     bool                        m_should_detach;   /// Should we detach if the process object goes away with an explicit call to Kill or Detach?

Modified: lldb/trunk/source/Commands/CommandObjectProcess.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectProcess.cpp?rev=238313&r1=238312&r2=238313&view=diff
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectProcess.cpp (original)
+++ lldb/trunk/source/Commands/CommandObjectProcess.cpp Wed May 27 07:40:32 2015
@@ -270,7 +270,7 @@ protected:
                 // There is a race condition where this thread will return up the call stack to the main command
                 // handler and show an (lldb) prompt before HandlePrivateEvent (from PrivateStateThread) has
                 // a chance to call PushProcessIOHandler().
-                process_sp->SyncIOHandler(2000);
+                process_sp->SyncIOHandler (0, 2000);
 
                 const char *data = stream.GetData();
                 if (data && strlen(data) > 0)
@@ -762,6 +762,8 @@ protected:
                 }
             }
 
+            const uint32_t iohandler_id = process->GetIOHandlerID();
+
             StreamString stream;
             Error error;
             if (synchronous_execution)
@@ -772,9 +774,9 @@ protected:
             if (error.Success())
             {
                 // There is a race condition where this thread will return up the call stack to the main command
-                // handler and show an (lldb) prompt before HandlePrivateEvent (from PrivateStateThread) has
-                // a chance to call PushProcessIOHandler().
-                process->SyncIOHandler(2000);
+                 // handler and show an (lldb) prompt before HandlePrivateEvent (from PrivateStateThread) has
+                 // a chance to call PushProcessIOHandler().
+                process->SyncIOHandler(iohandler_id, 2000);
 
                 result.AppendMessageWithFormat ("Process %" PRIu64 " resuming\n", process->GetID());
                 if (synchronous_execution)

Modified: lldb/trunk/source/Commands/CommandObjectThread.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectThread.cpp?rev=238313&r1=238312&r2=238313&view=diff
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectThread.cpp (original)
+++ lldb/trunk/source/Commands/CommandObjectThread.cpp Wed May 27 07:40:32 2015
@@ -675,6 +675,8 @@ protected:
 
             process->GetThreadList().SetSelectedThreadByID (thread->GetID());
 
+            const uint32_t iohandler_id = process->GetIOHandlerID();
+
             StreamString stream;
             Error error;
             if (synchronous_execution)
@@ -685,7 +687,7 @@ protected:
             // There is a race condition where this thread will return up the call stack to the main command handler
             // and show an (lldb) prompt before HandlePrivateEvent (from PrivateStateThread) has
             // a chance to call PushProcessIOHandler().
-            process->SyncIOHandler(2000);
+            process->SyncIOHandler(iohandler_id, 2000);
 
             if (synchronous_execution)
             {

Modified: lldb/trunk/source/Core/Debugger.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/Debugger.cpp?rev=238313&r1=238312&r2=238313&view=diff
==============================================================================
--- lldb/trunk/source/Core/Debugger.cpp (original)
+++ lldb/trunk/source/Core/Debugger.cpp Wed May 27 07:40:32 2015
@@ -885,34 +885,27 @@ Debugger::ClearIOHandlers ()
     {
         IOHandlerSP reader_sp (m_input_reader_stack.Top());
         if (reader_sp)
-        {
-            m_input_reader_stack.Pop();
-            reader_sp->SetIsDone(true);
-            reader_sp->Cancel();
-        }
+            PopIOHandler (reader_sp);
     }
 }
 
 void
 Debugger::ExecuteIOHandlers()
 {
-    
     while (1)
     {
         IOHandlerSP reader_sp(m_input_reader_stack.Top());
         if (!reader_sp)
             break;
 
-        reader_sp->Activate();
         reader_sp->Run();
-        reader_sp->Deactivate();
 
         // Remove all input readers that are done from the top of the stack
         while (1)
         {
             IOHandlerSP top_reader_sp = m_input_reader_stack.Top();
             if (top_reader_sp && top_reader_sp->GetIsDone())
-                m_input_reader_stack.Pop();
+                PopIOHandler (top_reader_sp);
             else
                 break;
         }
@@ -926,6 +919,12 @@ Debugger::IsTopIOHandler (const lldb::IO
     return m_input_reader_stack.IsTop (reader_sp);
 }
 
+void
+Debugger::PrintAsync (const char *s, size_t len, bool is_stdout)
+{
+    lldb::StreamFileSP stream = is_stdout ? GetOutputFile() : GetErrorFile();
+    m_input_reader_stack.PrintAsync(stream.get(), s, len);
+}
 
 ConstString
 Debugger::GetTopIOHandlerControlSequence(char ch)
@@ -949,25 +948,23 @@ void
 Debugger::RunIOHandler (const IOHandlerSP& reader_sp)
 {
     PushIOHandler (reader_sp);
-    
+
     IOHandlerSP top_reader_sp = reader_sp;
     while (top_reader_sp)
     {
-        top_reader_sp->Activate();
         top_reader_sp->Run();
-        top_reader_sp->Deactivate();
-        
+
         if (top_reader_sp.get() == reader_sp.get())
         {
             if (PopIOHandler (reader_sp))
                 break;
         }
-        
+
         while (1)
         {
             top_reader_sp = m_input_reader_stack.Top();
             if (top_reader_sp && top_reader_sp->GetIsDone())
-                m_input_reader_stack.Pop();
+                PopIOHandler (top_reader_sp);
             else
                 break;
         }
@@ -1030,87 +1027,67 @@ Debugger::PushIOHandler (const IOHandler
     if (!reader_sp)
         return;
  
-    // Got the current top input reader...
+    Mutex::Locker locker (m_input_reader_stack.GetMutex());
+
+    // Get the current top input reader...
     IOHandlerSP top_reader_sp (m_input_reader_stack.Top());
     
     // Don't push the same IO handler twice...
-    if (reader_sp.get() != top_reader_sp.get())
-    {
-        // Push our new input reader
-        m_input_reader_stack.Push (reader_sp);
+    if (reader_sp == top_reader_sp)
+        return;
 
-        // Interrupt the top input reader to it will exit its Run() function
-        // and let this new input reader take over
-        if (top_reader_sp)
-            top_reader_sp->Deactivate();
+    // Push our new input reader
+    m_input_reader_stack.Push (reader_sp);
+    reader_sp->Activate();
+
+    // Interrupt the top input reader to it will exit its Run() function
+    // and let this new input reader take over
+    if (top_reader_sp)
+    {
+        top_reader_sp->Deactivate();
+        top_reader_sp->Cancel();
     }
 }
 
 bool
 Debugger::PopIOHandler (const IOHandlerSP& pop_reader_sp)
 {
-    bool result = false;
-    
+    if (! pop_reader_sp)
+        return false;
+
     Mutex::Locker locker (m_input_reader_stack.GetMutex());
 
     // The reader on the stop of the stack is done, so let the next
     // read on the stack refresh its prompt and if there is one...
-    if (!m_input_reader_stack.IsEmpty())
-    {
-        IOHandlerSP reader_sp(m_input_reader_stack.Top());
-        
-        if (!pop_reader_sp || pop_reader_sp.get() == reader_sp.get())
-        {
-            reader_sp->Deactivate();
-            reader_sp->Cancel();
-            m_input_reader_stack.Pop ();
-            
-            reader_sp = m_input_reader_stack.Top();
-            if (reader_sp)
-                reader_sp->Activate();
+    if (m_input_reader_stack.IsEmpty())
+        return false;
 
-            result = true;
-        }
-    }
-    return result;
-}
+    IOHandlerSP reader_sp(m_input_reader_stack.Top());
 
-bool
-Debugger::HideTopIOHandler()
-{
-    Mutex::Locker locker;
-    
-    if (locker.TryLock(m_input_reader_stack.GetMutex()))
-    {
-        IOHandlerSP reader_sp(m_input_reader_stack.Top());
-        if (reader_sp)
-            reader_sp->Hide();
-        return true;
-    }
-    return false;
-}
+    if (pop_reader_sp != reader_sp)
+        return false;
 
-void
-Debugger::RefreshTopIOHandler()
-{
-    IOHandlerSP reader_sp(m_input_reader_stack.Top());
+    reader_sp->Deactivate();
+    reader_sp->Cancel();
+    m_input_reader_stack.Pop ();
+
+    reader_sp = m_input_reader_stack.Top();
     if (reader_sp)
-        reader_sp->Refresh();
-}
+        reader_sp->Activate();
 
+    return true;
+}
 
 StreamSP
 Debugger::GetAsyncOutputStream ()
 {
-    return StreamSP (new StreamAsynchronousIO (GetCommandInterpreter(),
-                                               CommandInterpreter::eBroadcastBitAsynchronousOutputData));
+    return StreamSP (new StreamAsynchronousIO (*this, true));
 }
 
 StreamSP
 Debugger::GetAsyncErrorStream ()
 {
-    return StreamSP (new StreamAsynchronousIO (GetCommandInterpreter(),
-                                               CommandInterpreter::eBroadcastBitAsynchronousErrorData));
+    return StreamSP (new StreamAsynchronousIO (*this, false));
 }    
 
 size_t
@@ -1396,14 +1373,14 @@ Debugger::HandleBreakpointEvent (const E
         if (num_new_locations > 0)
         {
             BreakpointSP breakpoint = Breakpoint::BreakpointEventData::GetBreakpointFromEvent(event_sp);
-            StreamFileSP output_sp (GetOutputFile());
+            StreamSP output_sp (GetAsyncOutputStream());
             if (output_sp)
             {
                 output_sp->Printf("%d location%s added to breakpoint %d\n",
                                   num_new_locations,
                                   num_new_locations == 1 ? "" : "s",
                                   breakpoint->GetID());
-                RefreshTopIOHandler();
+                output_sp->Flush();
             }
         }
     }
@@ -1490,8 +1467,8 @@ Debugger::HandleProcessEvent (const Even
     const uint32_t event_type = event_sp->GetType();
     ProcessSP process_sp = Process::ProcessEventData::GetProcessFromEvent(event_sp.get());
 
-    StreamString output_stream;
-    StreamString error_stream;
+    StreamSP output_stream_sp = GetAsyncOutputStream();
+    StreamSP error_stream_sp = GetAsyncErrorStream();
     const bool gui_enabled = IsForwardingEvents();
 
     if (!gui_enabled)
@@ -1499,47 +1476,43 @@ Debugger::HandleProcessEvent (const Even
         bool pop_process_io_handler = false;
         assert (process_sp);
 
-        if (event_type & Process::eBroadcastBitSTDOUT || event_type & Process::eBroadcastBitStateChanged)
+        bool state_is_stopped = false;
+        const bool got_state_changed = (event_type & Process::eBroadcastBitStateChanged) != 0;
+        const bool got_stdout = (event_type & Process::eBroadcastBitSTDOUT) != 0;
+        const bool got_stderr = (event_type & Process::eBroadcastBitSTDERR) != 0;
+        if (got_state_changed)
         {
-            GetProcessSTDOUT (process_sp.get(), &output_stream);
+            StateType event_state = Process::ProcessEventData::GetStateFromEvent (event_sp.get());
+            state_is_stopped = StateIsStoppedState(event_state, false);
         }
 
-        if (event_type & Process::eBroadcastBitSTDERR || event_type & Process::eBroadcastBitStateChanged)
+        // Display running state changes first before any STDIO
+        if (got_state_changed && !state_is_stopped)
         {
-            GetProcessSTDERR (process_sp.get(), &error_stream);
+            Process::HandleProcessStateChangedEvent (event_sp, output_stream_sp.get(), pop_process_io_handler);
         }
 
-        if (event_type & Process::eBroadcastBitStateChanged)
+        // Now display and STDOUT
+        if (got_stdout || got_state_changed)
         {
-            Process::HandleProcessStateChangedEvent (event_sp, &output_stream, pop_process_io_handler);
+            GetProcessSTDOUT (process_sp.get(), output_stream_sp.get());
         }
 
-        if (output_stream.GetSize() || error_stream.GetSize())
+        // Now display and STDERR
+        if (got_stderr || got_state_changed)
         {
-            StreamFileSP error_stream_sp (GetOutputFile());
-            bool top_io_handler_hid = false;
-
-            if (process_sp->ProcessIOHandlerExists() && process_sp->ProcessIOHandlerIsActive() == false)
-                top_io_handler_hid = HideTopIOHandler();
-
-            if (output_stream.GetSize())
-            {
-                StreamFileSP output_stream_sp (GetOutputFile());
-                if (output_stream_sp)
-                    output_stream_sp->Write (output_stream.GetData(), output_stream.GetSize());
-            }
-
-            if (error_stream.GetSize())
-            {
-                StreamFileSP error_stream_sp (GetErrorFile());
-                if (error_stream_sp)
-                    error_stream_sp->Write (error_stream.GetData(), error_stream.GetSize());
-            }
+            GetProcessSTDERR (process_sp.get(), error_stream_sp.get());
+        }
 
-            if (top_io_handler_hid)
-                RefreshTopIOHandler();
+        // Now display any stopped state changes after any STDIO
+        if (got_state_changed && state_is_stopped)
+        {
+            Process::HandleProcessStateChangedEvent (event_sp, output_stream_sp.get(), pop_process_io_handler);
         }
 
+        output_stream_sp->Flush();
+        error_stream_sp->Flush();
+
         if (pop_process_io_handler)
             process_sp->PopProcessIOHandler();
     }
@@ -1558,10 +1531,7 @@ Debugger::HandleThreadEvent (const Event
         ThreadSP thread_sp (Thread::ThreadEventData::GetThreadFromEvent (event_sp.get()));
         if (thread_sp)
         {
-            HideTopIOHandler();
-            StreamFileSP stream_sp (GetOutputFile());
-            thread_sp->GetStatus(*stream_sp, 0, 1, 1);
-            RefreshTopIOHandler();
+            thread_sp->GetStatus(*GetAsyncOutputStream(), 0, 1, 1);
         }
     }
 }
@@ -1655,13 +1625,11 @@ Debugger::DefaultEventHandler()
                             const char *data = reinterpret_cast<const char *>(EventDataBytes::GetBytesFromEvent (event_sp.get()));
                             if (data && data[0])
                             {
-                                StreamFileSP error_sp (GetErrorFile());
+                                StreamSP error_sp (GetAsyncErrorStream());
                                 if (error_sp)
                                 {
-                                    HideTopIOHandler();
                                     error_sp->PutCString(data);
                                     error_sp->Flush();
-                                    RefreshTopIOHandler();
                                 }
                             }
                         }
@@ -1670,13 +1638,11 @@ Debugger::DefaultEventHandler()
                             const char *data = reinterpret_cast<const char *>(EventDataBytes::GetBytesFromEvent (event_sp.get()));
                             if (data && data[0])
                             {
-                                StreamFileSP output_sp (GetOutputFile());
+                                StreamSP output_sp (GetAsyncOutputStream());
                                 if (output_sp)
                                 {
-                                    HideTopIOHandler();
                                     output_sp->PutCString(data);
                                     output_sp->Flush();
-                                    RefreshTopIOHandler();
                                 }
                             }
                         }

Modified: lldb/trunk/source/Core/IOHandler.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/IOHandler.cpp?rev=238313&r1=238312&r2=238313&view=diff
==============================================================================
--- lldb/trunk/source/Core/IOHandler.cpp (original)
+++ lldb/trunk/source/Core/IOHandler.cpp Wed May 27 07:40:32 2015
@@ -169,6 +169,17 @@ IOHandler::WaitForPop ()
     m_popped.WaitForValueEqualTo(true);
 }
 
+void
+IOHandlerStack::PrintAsync (Stream *stream, const char *s, size_t len)
+{
+    if (stream)
+    {
+        Mutex::Locker locker (m_mutex);
+        if (m_top)
+            m_top->PrintAsync (stream, s, len);
+    }
+}
+
 IOHandlerConfirm::IOHandlerConfirm (Debugger &debugger,
                                     const char *prompt,
                                     bool default_response) :
@@ -740,47 +751,11 @@ IOHandlerEditline::Run ()
 }
 
 void
-IOHandlerEditline::Hide ()
-{
-#ifndef LLDB_DISABLE_LIBEDIT
-    if (m_editline_ap)
-        m_editline_ap->Hide();
-#endif
-}
-
-
-void
-IOHandlerEditline::Refresh ()
-{
-#ifndef LLDB_DISABLE_LIBEDIT
-    if (m_editline_ap)
-    {
-        m_editline_ap->Refresh();
-    }
-    else if (m_editing)
-    {
-#endif
-        const char *prompt = GetPrompt();
-        if (prompt && prompt[0])
-        {
-            FILE *out = GetOutputFILE();
-            if (out)
-            {
-                ::fprintf(out, "%s", prompt);
-                ::fflush(out);
-            }
-        }
-#ifndef LLDB_DISABLE_LIBEDIT
-    }
-#endif
-}
-
-void
 IOHandlerEditline::Cancel ()
 {
 #ifndef LLDB_DISABLE_LIBEDIT
     if (m_editline_ap)
-        m_editline_ap->Interrupt ();
+        m_editline_ap->Cancel ();
 #endif
 }
 
@@ -807,6 +782,17 @@ IOHandlerEditline::GotEOF()
 #endif
 }
 
+void
+IOHandlerEditline::PrintAsync (Stream *stream, const char *s, size_t len)
+{
+#ifndef LLDB_DISABLE_LIBEDIT
+    if (m_editline_ap)
+        m_editline_ap->PrintAsync(stream, s, len);
+    else
+#endif
+        IOHandler::PrintAsync(stream, s, len);
+}
+
 // we may want curses to be disabled for some builds
 // for instance, windows
 #ifndef LLDB_DISABLE_CURSES
@@ -5618,17 +5604,6 @@ IOHandlerCursesGUI::~IOHandlerCursesGUI
 }
 
 void
-IOHandlerCursesGUI::Hide ()
-{
-}
-
-
-void
-IOHandlerCursesGUI::Refresh ()
-{
-}
-
-void
 IOHandlerCursesGUI::Cancel ()
 {
 }

Modified: lldb/trunk/source/Core/StreamAsynchronousIO.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/StreamAsynchronousIO.cpp?rev=238313&r1=238312&r2=238313&view=diff
==============================================================================
--- lldb/trunk/source/Core/StreamAsynchronousIO.cpp (original)
+++ lldb/trunk/source/Core/StreamAsynchronousIO.cpp Wed May 27 07:40:32 2015
@@ -7,22 +7,20 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include <stdio.h>
+#include "lldb/Core/StreamAsynchronousIO.h"
 
 #include "lldb/lldb-private.h"
-#include "lldb/Core/Broadcaster.h"
-#include "lldb/Core/Event.h"
-#include "lldb/Core/StreamAsynchronousIO.h"
+#include "lldb/Core/Debugger.h"
 
 using namespace lldb;
 using namespace lldb_private;
 
 
-StreamAsynchronousIO::StreamAsynchronousIO (Broadcaster &broadcaster, uint32_t broadcast_event_type) :
+StreamAsynchronousIO::StreamAsynchronousIO (Debugger &debugger, bool for_stdout) :
     Stream (0, 4, eByteOrderBig),
-    m_broadcaster (broadcaster),
-    m_broadcast_event_type (broadcast_event_type),
-    m_accumulated_data ()
+    m_debugger (debugger),
+    m_data (),
+    m_for_stdout (for_stdout)
 {
 }
 
@@ -35,19 +33,16 @@ StreamAsynchronousIO::~StreamAsynchronou
 void
 StreamAsynchronousIO::Flush ()
 {
-    if (!m_accumulated_data.empty())
+    if (!m_data.empty())
     {
-        std::unique_ptr<EventDataBytes> data_bytes_ap (new EventDataBytes);
-        // Let's swap the bytes to avoid LARGE string copies.
-        data_bytes_ap->SwapBytes (m_accumulated_data);
-        EventSP new_event_sp (new Event (m_broadcast_event_type, data_bytes_ap.release()));
-        m_broadcaster.BroadcastEvent (new_event_sp);
+        m_debugger.PrintAsync (m_data.data(), m_data.size(), m_for_stdout);
+        m_data = std::move(std::string());
     }
 }
 
 size_t
 StreamAsynchronousIO::Write (const void *s, size_t length)
 {
-    m_accumulated_data.append ((const char *)s, length);
+    m_data.append ((const char *)s, length);
     return length;
 }

Modified: lldb/trunk/source/Host/common/Editline.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/Editline.cpp?rev=238313&r1=238312&r2=238313&view=diff
==============================================================================
--- lldb/trunk/source/Host/common/Editline.cpp (original)
+++ lldb/trunk/source/Host/common/Editline.cpp Wed May 27 07:40:32 2015
@@ -20,6 +20,7 @@
 #include "lldb/Host/FileSystem.h"
 #include "lldb/Host/Host.h"
 #include "lldb/Host/Mutex.h"
+#include "lldb/Utility/LLDBAssert.h"
 
 using namespace lldb_private;
 using namespace lldb_private::line_editor;
@@ -581,9 +582,22 @@ Editline::GetCharacter (EditLineCharType
     {
         lldb::ConnectionStatus status = lldb::eConnectionStatusSuccess;
         char ch = 0;
-        m_editor_getting_char = true;
+
+        // This mutex is locked by our caller (GetLine). Unlock it while we read a character
+        // (blocking operation), so we do not hold the mutex indefinitely. This gives a chance
+        // for someone to interrupt us. After Read returns, immediately lock the mutex again and
+        // check if we were interrupted.
+        m_output_mutex.Unlock();
         int read_count = m_input_connection.Read(&ch, 1, UINT32_MAX, status, NULL);
-        m_editor_getting_char = false;
+        m_output_mutex.Lock();
+        if (m_editor_status == EditorStatus::Interrupted)
+        {
+            while (read_count > 0 && status == lldb::eConnectionStatusSuccess)
+                read_count = m_input_connection.Read(&ch, 1, UINT32_MAX, status, NULL);
+            lldbassert(status == lldb::eConnectionStatusInterrupted);
+            return 0;
+        }
+
         if (read_count)
         {
 #if LLDB_EDITLINE_USE_WCHAR
@@ -602,14 +616,12 @@ Editline::GetCharacter (EditLineCharType
         {
             switch (status)
             {
-                case lldb::eConnectionStatusInterrupted:
-                    m_editor_status = EditorStatus::Interrupted;
-                    printf ("^C\n");
-                    return 0;
-                    
                 case lldb::eConnectionStatusSuccess:         // Success
                     break;
                     
+                case lldb::eConnectionStatusInterrupted:
+                    lldbassert(0 && "Interrupts should have been handled above.");
+
                 case lldb::eConnectionStatusError:           // Check GetError() for details
                 case lldb::eConnectionStatusTimedOut:        // Request timed out
                 case lldb::eConnectionStatusEndOfFile:       // End-of-file encountered
@@ -1252,41 +1264,31 @@ Editline::GetCurrentLine()
     return m_current_line_index;
 }
 
-void
-Editline::Hide()
-{
-    // Make sure we're at a stable location waiting for input
-    while (m_editor_status == EditorStatus::Editing && !m_editor_getting_char)
-    {
-        usleep(100000);
-    }
-    
-    // Clear the existing input
-    if (m_editor_status == EditorStatus::Editing)
-    {
-        MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart);
-        fprintf(m_output_file, ANSI_CLEAR_BELOW);
-    }
-}
-
-void
-Editline::Refresh()
+bool
+Editline::Interrupt()
 {
-    if (m_editor_status == EditorStatus::Editing)
-    {
-        DisplayInput();
-        MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor);
+    bool result = true;
+    Mutex::Locker locker(m_output_mutex);
+    if (m_editor_status == EditorStatus::Editing) {
+        fprintf(m_output_file, "^C\n");
+        result = m_input_connection.InterruptRead();
     }
+    m_editor_status = EditorStatus::Interrupted;
+    return result;
 }
 
 bool
-Editline::Interrupt()
+Editline::Cancel()
 {
-    if (m_editor_status == EditorStatus::Editing)
-    {
-        return m_input_connection.InterruptRead();
+    bool result = true;
+    Mutex::Locker locker(m_output_mutex);
+    if (m_editor_status == EditorStatus::Editing) {
+        MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart);
+        fprintf(m_output_file, ANSI_CLEAR_BELOW);
+        result = m_input_connection.InterruptRead();
     }
-    return false; // Interrupt not handled as we weren't getting a line or lines
+    m_editor_status = EditorStatus::Interrupted;
+    return result;
 }
 
 void
@@ -1321,14 +1323,23 @@ Editline::GetLine (std::string &line, bo
     m_input_lines = std::vector<EditLineStringType>();
     m_input_lines.insert (m_input_lines.begin(), EditLineConstString(""));
     
+    Mutex::Locker locker(m_output_mutex);
+
+    lldbassert(m_editor_status != EditorStatus::Editing);
+    if (m_editor_status == EditorStatus::Interrupted)
+    {
+        m_editor_status = EditorStatus::Complete;
+        interrupted = true;
+        return true;
+    }
+
     SetCurrentLine (0);
     m_in_history = false;
     m_editor_status = EditorStatus::Editing;
-    m_editor_getting_char = false;
     m_revert_cursor_index = -1;
 
 #ifdef USE_SETUPTERM_WORKAROUND
-    setupterm((char *)0, fileno(m_output_file), (int *)0);
+        setupterm((char *)0, fileno(m_output_file), (int *)0);
 #endif
 
     int count;
@@ -1366,12 +1377,12 @@ Editline::GetLines (int first_line_numbe
     m_input_lines = std::vector<EditLineStringType>();
     m_input_lines.insert (m_input_lines.begin(), EditLineConstString(""));
     
+    Mutex::Locker locker(m_output_mutex);
     // Begin the line editing loop
     DisplayInput();
     SetCurrentLine (0);
     MoveCursor (CursorLocation::BlockEnd, CursorLocation::BlockStart);
     m_editor_status = EditorStatus::Editing;
-    m_editor_getting_char = false;
     m_in_history = false;
 
     m_revert_cursor_index = -1;
@@ -1396,3 +1407,21 @@ Editline::GetLines (int first_line_numbe
     }
     return m_editor_status != EditorStatus::EndOfInput;
 }
+
+void
+Editline::PrintAsync (Stream *stream, const char *s, size_t len)
+{
+    Mutex::Locker locker(m_output_mutex);
+    if (m_editor_status == EditorStatus::Editing)
+    {
+        MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart);
+        fprintf(m_output_file, ANSI_CLEAR_BELOW);
+    }
+    stream->Write (s, len);
+    stream->Flush();
+    if (m_editor_status == EditorStatus::Editing)
+    {
+        DisplayInput();
+        MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor);
+    }
+}

Modified: lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp?rev=238313&r1=238312&r2=238313&view=diff
==============================================================================
--- lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp (original)
+++ lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp Wed May 27 07:40:32 2015
@@ -734,22 +734,21 @@ public:
         
     }
     
-    virtual
-    ~IOHandlerPythonInterpreter()
+    ~IOHandlerPythonInterpreter() override
     {
         
     }
     
-    virtual ConstString
-    GetControlSequence (char ch)
+    ConstString
+    GetControlSequence (char ch) override
     {
         if (ch == 'd')
             return ConstString("quit()\n");
         return ConstString();
     }
 
-    virtual void
-    Run ()
+    void
+    Run () override
     {
         if (m_python)
         {
@@ -795,32 +794,20 @@ public:
         SetIsDone(true);
     }
 
-    virtual void
-    Hide ()
-    {
-        
-    }
-    
-    virtual void
-    Refresh ()
-    {
-        
-    }
-
-    virtual void
-    Cancel ()
+    void
+    Cancel () override
     {
         
     }
 
-    virtual bool
-    Interrupt ()
+    bool
+    Interrupt () override
     {
         return m_python->Interrupt();
     }
     
-    virtual void
-    GotEOF()
+    void
+    GotEOF() override
     {
         
     }

Modified: lldb/trunk/source/Target/Process.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Process.cpp?rev=238313&r1=238312&r2=238313&view=diff
==============================================================================
--- lldb/trunk/source/Target/Process.cpp (original)
+++ lldb/trunk/source/Target/Process.cpp Wed May 27 07:40:32 2015
@@ -740,7 +740,7 @@ Process::Process(Target &target, Listene
     m_stderr_data (),
     m_profile_data_comm_mutex (Mutex::eMutexTypeRecursive),
     m_profile_data (),
-    m_iohandler_sync (false),
+    m_iohandler_sync (0),
     m_memory_cache (*this),
     m_allocated_memory_cache (*this),
     m_should_detach (false),
@@ -949,33 +949,21 @@ Process::GetNextEvent (EventSP &event_sp
     return state;
 }
 
-bool
-Process::SyncIOHandler (uint64_t timeout_msec)
+void
+Process::SyncIOHandler (uint32_t iohandler_id, uint64_t timeout_msec)
 {
-    bool timed_out = false;
-
     // don't sync (potentially context switch) in case where there is no process IO
-    if (m_process_input_reader)
-    {
-        TimeValue timeout = TimeValue::Now();
-        timeout.OffsetWithMicroSeconds(timeout_msec*1000);
-
-        m_iohandler_sync.WaitForValueEqualTo(true, &timeout, &timed_out);
-
-        Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
-        if(log)
-        {
-            if(timed_out)
-                log->Printf ("Process::%s pid %" PRIu64 " (timeout=%" PRIu64 "ms): FAIL", __FUNCTION__, GetID (), timeout_msec);
-            else
-                log->Printf ("Process::%s pid %" PRIu64 ": SUCCESS", __FUNCTION__, GetID ());
-        }
+    if (! m_process_input_reader)
+        return;
 
-        // reset sync one-shot so it will be ready for next launch
-        m_iohandler_sync.SetValue(false, eBroadcastNever);
-    }
+    TimeValue timeout = TimeValue::Now();
+    timeout.OffsetWithMicroSeconds(timeout_msec*1000);
+    uint32_t new_iohandler_id = 0;
+    m_iohandler_sync.WaitForValueNotEqualTo(iohandler_id, new_iohandler_id, &timeout);
 
-    return !timed_out;
+    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+    if (log)
+        log->Printf("Process::%s waited for m_iohandler_sync to change from %u, new value is %u", __FUNCTION__, iohandler_id, new_iohandler_id);
 }
 
 StateType
@@ -4477,12 +4465,15 @@ Process::HandlePrivateEvent (EventSP &ev
             // Or don't push it if we are launching since it will come up stopped.
             if (!GetTarget().GetDebugger().IsForwardingEvents() && new_state != eStateLaunching &&
                 new_state != eStateAttaching)
+            {
                 PushProcessIOHandler ();
-            m_iohandler_sync.SetValue(true, eBroadcastAlways);
+                m_iohandler_sync.SetValue(m_iohandler_sync.GetValue()+1, eBroadcastAlways);
+                if (log)
+                    log->Printf("Process::%s updated m_iohandler_sync to %d", __FUNCTION__, m_iohandler_sync.GetValue());
+            }
         }
         else if (StateIsStoppedState(new_state, false))
         {
-            m_iohandler_sync.SetValue(false, eBroadcastNever);
             if (!Process::ProcessEventData::GetRestartedFromEvent(event_sp.get()))
             {
                 // If the lldb_private::Debugger is handling the events, we don't
@@ -5125,8 +5116,8 @@ public:
     // Each IOHandler gets to run until it is done. It should read data
     // from the "in" and place output into "out" and "err and return
     // when done.
-    virtual void
-    Run ()
+    void
+    Run () override
     {
         if (m_read_file.IsValid() && m_write_file.IsValid())
         {
@@ -5204,33 +5195,16 @@ public:
             SetIsDone(true);
     }
     
-    // Hide any characters that have been displayed so far so async
-    // output can be displayed. Refresh() will be called after the
-    // output has been displayed.
-    virtual void
-    Hide ()
-    {
-        
-    }
-    // Called when the async output has been received in order to update
-    // the input reader (refresh the prompt and redisplay any current
-    // line(s) that are being edited
-    virtual void
-    Refresh ()
-    {
-        
-    }
-    
-    virtual void
-    Cancel ()
+    void
+    Cancel () override
     {
         char ch = 'q';  // Send 'q' for quit
         size_t bytes_written = 0;
         m_pipe.Write(&ch, 1, bytes_written);
     }
 
-    virtual bool
-    Interrupt ()
+    bool
+    Interrupt () override
     {
         // Do only things that are safe to do in an interrupt context (like in
         // a SIGINT handler), like write 1 byte to a file descriptor. This will
@@ -5263,8 +5237,8 @@ public:
         return false;
     }
     
-    virtual void
-    GotEOF()
+    void
+    GotEOF() override
     {
         
     }
@@ -5313,6 +5287,10 @@ Process::PushProcessIOHandler ()
     IOHandlerSP io_handler_sp (m_process_input_reader);
     if (io_handler_sp)
     {
+        Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+        if (log)
+            log->Printf("Process::%s pushing IO handler", __FUNCTION__);
+
         io_handler_sp->SetIsDone(false);
         m_target.GetDebugger().PushIOHandler (io_handler_sp);
         return true;





More information about the lldb-commits mailing list