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).

llvm-svn: 130721
diff --git a/lldb/tools/driver/IOChannel.cpp b/lldb/tools/driver/IOChannel.cpp
index 9bf2b8e..6c2c3d9 100644
--- a/lldb/tools/driver/IOChannel.cpp
+++ b/lldb/tools/driver/IOChannel.cpp
@@ -29,10 +29,6 @@
 const char *g_default_prompt = "(lldb) ";
 PromptMap g_prompt_map;
 
-#define NSEC_PER_USEC   1000ull
-#define USEC_PER_SEC    1000000ull
-#define NSEC_PER_SEC    1000000000ull
-
 static const char*
 el_prompt(EditLine *el)
 {
@@ -100,16 +96,16 @@
         const char *comment = "\nAvailable completions:";
 
         int num_elements = num_completions + 1;
-        OutWrite(comment,  strlen (comment));
+        OutWrite(comment,  strlen (comment), NO_ASYNC);
         if (num_completions < page_size)
         {
             for (int i = 1; i < num_elements; i++)
             {
                 completion_str = completions.GetStringAtIndex(i);
-                OutWrite("\n\t", 2);
-                OutWrite(completion_str, strlen (completion_str));
+                OutWrite("\n\t", 2, NO_ASYNC);
+                OutWrite(completion_str, strlen (completion_str), NO_ASYNC);
             }
-            OutWrite ("\n", 1);
+            OutWrite ("\n", 1, NO_ASYNC);
         }
         else
         {
@@ -124,17 +120,17 @@
                 for (; cur_pos < endpoint; cur_pos++)
                 {
                     completion_str = completions.GetStringAtIndex(cur_pos);
-                    OutWrite("\n\t", 2);
-                    OutWrite(completion_str, strlen (completion_str));
+                    OutWrite("\n\t", 2, NO_ASYNC);
+                    OutWrite(completion_str, strlen (completion_str), NO_ASYNC);
                 }
 
                 if (cur_pos >= num_elements)
                 {
-                    OutWrite("\n", 1);
+                    OutWrite("\n", 1, NO_ASYNC);
                     break;
                 }
 
-                OutWrite("\nMore (Y/n/a): ", strlen ("\nMore (Y/n/a): "));
+                OutWrite("\nMore (Y/n/a): ", strlen ("\nMore (Y/n/a): "), NO_ASYNC);
                 reply = 'n';
                 got_char = el_getc(m_edit_line, &reply);
                 if (got_char == -1 || reply == 'n')
@@ -154,8 +150,9 @@
 
 IOChannel::IOChannel
 (
-    FILE *in,
-    FILE *out,
+    FILE *editline_in,
+    FILE *editline_out,
+    FILE *out,  
     FILE *err,
     Driver *driver
 ) :
@@ -169,10 +166,12 @@
     m_err_file (err),
     m_command_queue (),
     m_completion_key ("\t"),
-    m_edit_line (::el_init (SBHostOS::GetProgramFileSpec().GetFilename(), in, out, err)),
+    m_edit_line (::el_init (SBHostOS::GetProgramFileSpec().GetFilename(), editline_in, editline_out,  editline_out)),
     m_history (history_init()),
     m_history_event(),
-    m_getting_command (false)
+    m_getting_command (false),
+    m_expecting_prompt (false),
+	m_prompt_str ()
 {
     assert (m_edit_line);
     ::el_set (m_edit_line, EL_PROMPT, el_prompt);
@@ -252,6 +251,36 @@
     }
 }
 
+void
+IOChannel::LibeditOutputBytesReceived (void *baton, const void *src, size_t src_len)
+{
+	// Make this a member variable.
+    // static std::string prompt_str;
+    IOChannel *io_channel = (IOChannel *) baton;
+    const char *bytes = (const char *) src;
+
+    if (io_channel->IsGettingCommand() && io_channel->m_expecting_prompt)
+    {
+        io_channel->m_prompt_str.append (bytes, src_len);
+		// Log this to make sure the prompt is really what you think it is.
+        if (io_channel->m_prompt_str.find (el_prompt(io_channel->m_edit_line)) == 0)
+        {
+            io_channel->m_expecting_prompt = false;
+            io_channel->OutWrite (io_channel->m_prompt_str.c_str(), 
+                                  io_channel->m_prompt_str.size(), NO_ASYNC);
+            io_channel->m_prompt_str.clear();
+        }
+		else 
+			assert (io_channel->m_prompt_str.find (el_prompt(io_channel->m_edit_line)) == std::string::npos);
+    }
+    else
+    {
+        if (io_channel->m_prompt_str.size() > 0)
+            io_channel->m_prompt_str.clear();
+        io_channel->OutWrite (bytes, src_len, NO_ASYNC);
+    }
+}
+
 bool
 IOChannel::LibeditGetInput (std::string &new_line)
 {
@@ -262,12 +291,7 @@
         // Set boolean indicating whether or not el_gets is trying to get input (i.e. whether or not to attempt
         // to refresh the prompt after writing data).
         SetGettingCommand (true);
-        
-        // Get the current time just before calling el_gets; this is used by OutWrite, ErrWrite, and RefreshPrompt
-        // to make sure they have given el_gets enough time to write the prompt before they attempt to write
-        // anything.
-
-        ::gettimeofday (&m_enter_elgets_time, NULL);
+        m_expecting_prompt = true;
 
         // Call el_gets to prompt the user and read the user's input.
         const char *line = ::el_gets (m_edit_line, &line_len);
@@ -318,7 +342,9 @@
     listener.StartListeningForEvents (interpreter_broadcaster,
                                       SBCommandInterpreter::eBroadcastBitResetPrompt |
                                       SBCommandInterpreter::eBroadcastBitThreadShouldExit |
-                                      SBCommandInterpreter::eBroadcastBitQuitCommandReceived);
+                                      SBCommandInterpreter::eBroadcastBitQuitCommandReceived |
+                                      SBCommandInterpreter::eBroadcastBitAsynchronousOutputData |
+                                      SBCommandInterpreter::eBroadcastBitAsynchronousErrorData);
 
     listener.StartListeningForEvents (*this,
                                       IOChannel::eBroadcastBitThreadShouldExit);
@@ -392,6 +418,18 @@
                 case SBCommandInterpreter::eBroadcastBitQuitCommandReceived:
                     done = true;
                     break;
+                case SBCommandInterpreter::eBroadcastBitAsynchronousErrorData:
+                    {
+                        const char *data = SBEvent::GetCStringFromEvent (event);
+                        ErrWrite (data, strlen(data), ASYNC);
+                    }
+                    break;
+                case SBCommandInterpreter::eBroadcastBitAsynchronousOutputData:
+                    {
+                        const char *data = SBEvent::GetCStringFromEvent (event);
+                        OutWrite (data, strlen(data), ASYNC);
+                    }
+                    break;
                 }
             }
             else if (event.BroadcasterMatchesPtr (this))
@@ -448,60 +486,41 @@
     if (! IsGettingCommand())
         return;
 
-    // Compare the current time versus the last time el_gets was called.  If less than 40 milliseconds
-    // (40,0000 microseconds or 40,000,0000 nanoseconds) have elapsed, wait 40,0000 microseconds, to ensure el_gets had
-    // time to finish writing the prompt before we start writing here.
+	// If we haven't finished writing the prompt, there's no need to refresh it.
+    if (m_expecting_prompt)
+        return;
 
-    if (ElapsedNanoSecondsSinceEnteringElGets() < (40 * 1000 * 1000))
-        usleep (40 * 1000);
-
-    // Use the mutex to make sure OutWrite, ErrWrite and Refresh prompt do not interfere with
-    // each other's output.
-
-    IOLocker locker (m_output_mutex);
     ::el_set (m_edit_line, EL_REFRESH);
 }
 
 void
-IOChannel::OutWrite (const char *buffer, size_t len)
+IOChannel::OutWrite (const char *buffer, size_t len, bool asynchronous)
 {
     if (len == 0)
         return;
 
-    // Compare the current time versus the last time el_gets was called.  If less than
-    // 10000 microseconds (10000000 nanoseconds) have elapsed, wait 10000 microseconds, to ensure el_gets had time
-    // to finish writing the prompt before we start writing here.
-
-    if (ElapsedNanoSecondsSinceEnteringElGets() < 10000000)
-        usleep (10000);
-
-    {
-        // Use the mutex to make sure OutWrite, ErrWrite and Refresh prompt do not interfere with
-        // each other's output.
-        IOLocker locker (m_output_mutex);
-        ::fwrite (buffer, 1, len, m_out_file);
-    }
+    // Use the mutex to make sure OutWrite and ErrWrite do not interfere with each other's output.
+    IOLocker locker (m_output_mutex);
+    if (asynchronous)
+        ::fwrite ("\n", 1, 1, m_out_file);
+    ::fwrite (buffer, 1, len, m_out_file);
+    if (asynchronous)
+        m_driver->GetDebugger().NotifyTopInputReader (eInputReaderAsynchronousOutputWritten);
 }
 
 void
-IOChannel::ErrWrite (const char *buffer, size_t len)
+IOChannel::ErrWrite (const char *buffer, size_t len, bool asynchronous)
 {
     if (len == 0)
         return;
 
-    // Compare the current time versus the last time el_gets was called.  If less than
-    // 10000 microseconds (10000000 nanoseconds) have elapsed, wait 10000 microseconds, to ensure el_gets had time
-    // to finish writing the prompt before we start writing here.
-
-    if (ElapsedNanoSecondsSinceEnteringElGets() < 10000000)
-        usleep (10000);
-
-    {
-        // Use the mutex to make sure OutWrite, ErrWrite and Refresh prompt do not interfere with
-        // each other's output.
-        IOLocker locker (m_output_mutex);
-        ::fwrite (buffer, 1, len, m_err_file);
-    }
+    // Use the mutex to make sure OutWrite and ErrWrite do not interfere with each other's output.
+    IOLocker locker (m_output_mutex);
+    if (asynchronous)
+        ::fwrite ("\n", 1, 1, m_err_file);
+    ::fwrite (buffer, 1, len, m_err_file);
+    if (asynchronous)
+        m_driver->GetDebugger().NotifyTopInputReader (eInputReaderAsynchronousOutputWritten);
 }
 
 void
@@ -551,25 +570,6 @@
     m_getting_command = new_value;
 }
 
-uint64_t
-IOChannel::Nanoseconds (const struct timeval &time_val) const
-{
-    uint64_t nanoseconds = time_val.tv_sec * NSEC_PER_SEC + time_val.tv_usec * NSEC_PER_USEC;
-
-    return nanoseconds;
-}
-
-uint64_t
-IOChannel::ElapsedNanoSecondsSinceEnteringElGets ()
-{
-    if (! IsGettingCommand())
-        return 0;
-
-    struct timeval current_time;
-    ::gettimeofday (&current_time, NULL);
-    return (Nanoseconds (current_time) - Nanoseconds (m_enter_elgets_time));
-}
-
 IOLocker::IOLocker (pthread_mutex_t &mutex) :
     m_mutex_ptr (&mutex)
 {