This patch captures and serializes all output being written by the
command line driver, including the lldb prompt being output by
editline, the asynchronous process output & error messages, and
asynchronous messages written by target stop-hooks.

As part of this it introduces a new Stream class,
StreamAsynchronousIO.  A StreamAsynchronousIO object is created with a
broadcaster, who will eventually broadcast the stream's data for a
listener to handle, and an event type indicating what type of event
the broadcaster will broadcast.  When the Write method is called on a
StreamAsynchronousIO object, the data is appended to an internal
string.  When the Flush method is called on a StreamAsynchronousIO
object, it broadcasts it's data string and clears the string.

Anything in lldb-core that needs to generate asynchronous output for
the end-user should use the StreamAsynchronousIO objects.

I have also added a new notification type for InputReaders, to let
them know that a asynchronous output has been written. This is to
allow the input readers to, for example, refresh their prompts and
lines, if desired.  I added the case statements to all the input
readers to catch this notification, but I haven't added any code for
handling them yet (except to the IOChannel input reader).



git-svn-id: https://llvm.org/svn/llvm-project/llvdb/trunk@130721 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/tools/driver/Driver.cpp b/tools/driver/Driver.cpp
index 83e42fe..5107708 100644
--- a/tools/driver/Driver.cpp
+++ b/tools/driver/Driver.cpp
@@ -658,7 +658,7 @@
     size_t total_bytes = 0;
     while ((len = m_debugger.GetSelectedTarget().GetProcess().GetSTDOUT (stdio_buffer, sizeof (stdio_buffer))) > 0)
     {
-        m_io_channel_ap->OutWrite (stdio_buffer, len);
+        m_io_channel_ap->OutWrite (stdio_buffer, len, ASYNC);
         total_bytes += len;
     }
     return total_bytes;
@@ -673,7 +673,7 @@
     size_t total_bytes = 0;
     while ((len = m_debugger.GetSelectedTarget().GetProcess().GetSTDERR (stdio_buffer, sizeof (stdio_buffer))) > 0)
     {
-        m_io_channel_ap->ErrWrite (stdio_buffer, len);
+        m_io_channel_ap->ErrWrite (stdio_buffer, len, ASYNC);
         total_bytes += len;
     }
     return total_bytes;
@@ -755,24 +755,20 @@
     {
         // The process has stdout available, get it and write it out to the
         // appropriate place.
-        if (GetProcessSTDOUT ())
-            m_io_channel_ap->RefreshPrompt();
+        GetProcessSTDOUT ();
     }
     else if (event_type & SBProcess::eBroadcastBitSTDERR)
     {
         // The process has stderr available, get it and write it out to the
         // appropriate place.
-        if (GetProcessSTDERR ())
-            m_io_channel_ap->RefreshPrompt();
+        GetProcessSTDERR ();
     }
     else if (event_type & SBProcess::eBroadcastBitStateChanged)
     {
         // Drain all stout and stderr so we don't see any output come after
         // we print our prompts
-        if (GetProcessSTDOUT ()
-            || GetProcessSTDERR ())
-            m_io_channel_ap->RefreshPrompt();
-
+        GetProcessSTDOUT ();
+        GetProcessSTDERR ();
         // Something changed in the process;  get the event and report the process's current status and location to
         // the user.
         StateType event_state = SBProcess::GetStateFromEvent (event);
@@ -795,7 +791,7 @@
                 char message[1024];
                 int message_len = ::snprintf (message, sizeof(message), "Process %d %s\n", process.GetProcessID(),
                                               m_debugger.StateAsCString (event_state));
-                m_io_channel_ap->OutWrite(message, message_len);
+                m_io_channel_ap->OutWrite(message, message_len, ASYNC);
             }
             break;
 
@@ -807,9 +803,8 @@
             {
                 SBCommandReturnObject result;
                 m_debugger.GetCommandInterpreter().HandleCommand("process status", result, false);
-                m_io_channel_ap->ErrWrite (result.GetError(), result.GetErrorSize());
-                m_io_channel_ap->OutWrite (result.GetOutput(), result.GetOutputSize());
-                m_io_channel_ap->RefreshPrompt();
+                m_io_channel_ap->ErrWrite (result.GetError(), result.GetErrorSize(), ASYNC);
+                m_io_channel_ap->OutWrite (result.GetOutput(), result.GetOutputSize(), ASYNC);
             }
             break;
 
@@ -823,17 +818,15 @@
                 char message[1024];
                 int message_len = ::snprintf (message, sizeof(message), "Process %d stopped and was programmatically restarted.\n",
                                               process.GetProcessID());
-                m_io_channel_ap->OutWrite(message, message_len);
-                m_io_channel_ap->RefreshPrompt ();
+                m_io_channel_ap->OutWrite(message, message_len, ASYNC);
             }
             else
             {
                 SBCommandReturnObject result;
                 UpdateSelectedThread ();
                 m_debugger.GetCommandInterpreter().HandleCommand("process status", result, false);
-                m_io_channel_ap->ErrWrite (result.GetError(), result.GetErrorSize());
-                m_io_channel_ap->OutWrite (result.GetOutput(), result.GetOutputSize());
-                m_io_channel_ap->RefreshPrompt ();
+                m_io_channel_ap->ErrWrite (result.GetError(), result.GetErrorSize(), ASYNC);
+                m_io_channel_ap->OutWrite (result.GetOutput(), result.GetOutputSize(), ASYNC);
             }
             break;
         }
@@ -935,11 +928,16 @@
 
     case eInputReaderDeactivate:
         break;
+        
+    case eInputReaderAsynchronousOutputWritten:
+        if (driver->m_io_channel_ap.get() != NULL)
+            driver->m_io_channel_ap->RefreshPrompt();
+        break;
 
     case eInputReaderInterrupt:
         if (driver->m_io_channel_ap.get() != NULL)
         {
-            driver->m_io_channel_ap->OutWrite ("^C\n", 3);
+            driver->m_io_channel_ap->OutWrite ("^C\n", 3, NO_ASYNC);
             driver->m_io_channel_ap->RefreshPrompt();
         }
         break;
@@ -947,7 +945,7 @@
     case eInputReaderEndOfFile:
         if (driver->m_io_channel_ap.get() != NULL)
         {
-            driver->m_io_channel_ap->OutWrite ("^D\n", 3);
+            driver->m_io_channel_ap->OutWrite ("^D\n", 3, NO_ASYNC);
             driver->m_io_channel_ap->RefreshPrompt ();
         }
         write (driver->m_editline_pty.GetMasterFileDescriptor(), "quit\n", 5);
@@ -996,6 +994,36 @@
         }
     }
 
+    lldb_utility::PseudoTerminal editline_output_pty;
+    FILE *editline_output_slave_fh = NULL;
+    
+    if (editline_output_pty.OpenFirstAvailableMaster (O_RDWR|O_NOCTTY, error_str, sizeof (error_str)) == false)
+    {
+        ::fprintf (stderr, "error: failed to open output pseudo terminal : %s", error_str);
+        exit(1);
+    }
+    else
+    {
+        const char *output_slave_name = editline_output_pty.GetSlaveName (error_str, sizeof(error_str));
+        if (output_slave_name == NULL)
+        {
+            ::fprintf (stderr, "error: failed to get slave name for output pseudo terminal : %s", error_str);
+            exit(2);
+        }
+        else
+        {
+            editline_output_slave_fh = ::fopen (output_slave_name, "r+");
+            if (editline_output_slave_fh == NULL)
+            {
+                SBError error;
+                error.SetErrorToErrno();
+                ::fprintf (stderr, "error: failed to get open slave for output pseudo terminal : %s",
+                           error.GetCString());
+                exit(3);
+            }
+            ::setbuf (editline_output_slave_fh, NULL);
+        }
+    }
 
    // struct termios stdin_termios;
 
@@ -1038,7 +1066,19 @@
 //
     SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter();
 
-    m_io_channel_ap.reset (new IOChannel(m_editline_slave_fh, stdout, stderr, this));
+    m_io_channel_ap.reset (new IOChannel(m_editline_slave_fh, editline_output_slave_fh, stdout, stderr, this));
+
+    SBCommunication out_comm_2("driver.editline_output");
+    out_comm_2.SetCloseOnEOF (false);
+    out_comm_2.AdoptFileDesriptor (editline_output_pty.GetMasterFileDescriptor(), false);
+    out_comm_2.SetReadThreadBytesReceivedCallback (IOChannel::LibeditOutputBytesReceived, m_io_channel_ap.get());
+
+    if (out_comm_2.ReadThreadStart () == false)
+    {
+        ::fprintf (stderr, "error: failed to start libedit output read thread");
+        exit (5);
+    }
+
 
     struct winsize window_size;
     if (isatty (STDIN_FILENO)