aboutsummaryrefslogtreecommitdiff
path: root/tools/driver/IOChannel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/driver/IOChannel.cpp')
-rw-r--r--tools/driver/IOChannel.cpp121
1 files changed, 65 insertions, 56 deletions
diff --git a/tools/driver/IOChannel.cpp b/tools/driver/IOChannel.cpp
index 7adf2e4e85e9..7cba73aaae8c 100644
--- a/tools/driver/IOChannel.cpp
+++ b/tools/driver/IOChannel.cpp
@@ -7,6 +7,7 @@
//
//===----------------------------------------------------------------------===//
+#include "Platform.h"
#include "IOChannel.h"
#include <map>
@@ -73,7 +74,8 @@ void
IOChannel::EraseCharsBeforeCursor ()
{
const LineInfo *line_info = el_line(m_edit_line);
- el_deletestr(m_edit_line, line_info->cursor - line_info->buffer);
+ if (line_info != NULL)
+ el_deletestr(m_edit_line, line_info->cursor - line_info->buffer);
}
unsigned char
@@ -205,6 +207,7 @@ IOChannel::IOChannel
m_read_thread_should_exit (false),
m_out_file (out),
m_err_file (err),
+ m_editline_out (editline_out),
m_command_queue (),
m_completion_key ("\t"),
m_edit_line (::el_init (SBHostOS::GetProgramFileSpec().GetFilename(), editline_in, editline_out, editline_out)),
@@ -212,50 +215,35 @@ IOChannel::IOChannel
m_history_event(),
m_getting_command (false),
m_expecting_prompt (false),
- m_prompt_str (),
+ m_prompt_str (),
m_refresh_request_pending (false)
{
assert (m_edit_line);
- ::el_set (m_edit_line, EL_PROMPT, el_prompt);
- ::el_set (m_edit_line, EL_EDITOR, "emacs");
- ::el_set (m_edit_line, EL_HIST, history, m_history);
-
- el_set (m_edit_line, EL_ADDFN, "lldb_complete",
- "LLDB completion function",
- IOChannel::ElCompletionFn);
+ el_set (m_edit_line, EL_PROMPT, el_prompt);
+ el_set (m_edit_line, EL_EDITOR, "emacs");
+ el_set (m_edit_line, EL_HIST, history, m_history);
+ el_set (m_edit_line, EL_ADDFN, "lldb_complete", "LLDB completion function", IOChannel::ElCompletionFn);
el_set (m_edit_line, EL_BIND, m_completion_key, "lldb_complete", NULL);
el_set (m_edit_line, EL_BIND, "^r", "em-inc-search-prev", NULL); // Cycle through backwards search, entering string
el_set (m_edit_line, EL_BIND, "^w", "ed-delete-prev-word", NULL); // Delete previous word, behave like bash does.
- el_set (m_edit_line, EL_BIND, "\e[3~", "ed-delete-next-char", NULL); // Fix the delete key.
+ el_set (m_edit_line, EL_BIND, "\033[3~", "ed-delete-next-char", NULL); // Fix the delete key.
el_set (m_edit_line, EL_CLIENTDATA, this);
// Source $PWD/.editrc then $HOME/.editrc
- ::el_source (m_edit_line, NULL);
+ el_source (m_edit_line, NULL);
assert (m_history);
- ::history (m_history, &m_history_event, H_SETSIZE, 800);
- ::history (m_history, &m_history_event, H_SETUNIQUE, 1);
+ history (m_history, &m_history_event, H_SETSIZE, 800);
+ history (m_history, &m_history_event, H_SETUNIQUE, 1);
// Load history
HistorySaveLoad (false);
- // Set up mutex to make sure OutErr, OutWrite and RefreshPrompt do not interfere
- // with each other when writing.
-
- int error;
- ::pthread_mutexattr_t attr;
- error = ::pthread_mutexattr_init (&attr);
- assert (error == 0);
- error = ::pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
- assert (error == 0);
- error = ::pthread_mutex_init (&m_output_mutex, &attr);
- assert (error == 0);
- error = ::pthread_mutexattr_destroy (&attr);
- assert (error == 0);
-
// Initialize time that ::el_gets was last called.
-
m_enter_elgets_time.tv_sec = 0;
m_enter_elgets_time.tv_usec = 0;
+
+ // set the initial state to non flushed
+ m_output_flushed = false;
}
IOChannel::~IOChannel ()
@@ -274,8 +262,6 @@ IOChannel::~IOChannel ()
::el_end (m_edit_line);
m_edit_line = NULL;
}
-
- ::pthread_mutex_destroy (&m_output_mutex);
}
void
@@ -299,16 +285,24 @@ IOChannel::HistorySaveLoad (bool save)
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;
- IOLocker locker (io_channel->m_output_mutex);
+ std::lock_guard<std::recursive_mutex> locker(io_channel->m_output_mutex);
const char *bytes = (const char *) src;
+ bool flush = false;
+
+ // See if we have a 'flush' synchronization point in there.
+ // this is performed from 'fputc ('\0', m_editline_out);' in LibeditGetInput()
+ if (src_len > 0 && bytes[src_len-1] == '\0')
+ {
+ src_len--;
+ flush = true;
+ }
+
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.
+ // 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;
@@ -327,6 +321,15 @@ IOChannel::LibeditOutputBytesReceived (void *baton, const void *src, size_t src_
io_channel->m_refresh_request_pending = false;
io_channel->OutWrite (bytes, src_len, NO_ASYNC);
}
+
+#if !defined (_MSC_VER)
+ if (flush)
+ {
+ io_channel->m_output_flushed = true;
+ io_channel->m_output_cond.notify_all();
+ }
+#endif
+
}
IOChannel::LibeditGetInputResult
@@ -344,7 +347,28 @@ IOChannel::LibeditGetInput (std::string &new_line)
// Call el_gets to prompt the user and read the user's input.
const char *line = ::el_gets (m_edit_line, &line_len);
-
+
+#if !defined (_MSC_VER)
+ // Force the piped output from el_gets to finish processing.
+ // el_gets does an fflush internally, which is not sufficient here; it only
+ // writes the data into m_editline_out, but doesn't affect whether our worker
+ // thread will read that data yet. So we block here manually.
+ {
+ std::lock_guard<std::recursive_mutex> locker(m_output_mutex);
+ m_output_flushed = false;
+
+ // Write a synchronization point into the stream, so we can guarantee
+ // LibeditOutputBytesReceived has processed everything up till that mark.
+ fputc ('\0', m_editline_out);
+
+ while (!m_output_flushed)
+ {
+ // wait until the condition variable is signaled
+ m_output_cond.wait(m_output_mutex);
+ }
+ }
+#endif
+
// Re-set the boolean indicating whether or not el_gets is trying to get input.
SetGettingCommand (false);
@@ -379,7 +403,7 @@ IOChannel::LibeditGetInput (std::string &new_line)
return retval;
}
-void *
+thread_result_t
IOChannel::IOReadThread (void *ptr)
{
IOChannel *myself = static_cast<IOChannel *> (ptr);
@@ -502,8 +526,7 @@ IOChannel::Start ()
if (IS_VALID_LLDB_HOST_THREAD(m_read_thread))
return true;
- m_read_thread = SBHostOS::ThreadCreate ("<lldb.driver.commandline_io>", IOChannel::IOReadThread, this,
- NULL);
+ m_read_thread = SBHostOS::ThreadCreate("<lldb.driver.commandline_io>", (lldb::thread_func_t) IOChannel::IOReadThread, this, NULL);
return (IS_VALID_LLDB_HOST_THREAD(m_read_thread));
}
@@ -531,11 +554,11 @@ IOChannel::RefreshPrompt ()
{
// If we are not in the middle of getting input from the user, there is no need to
// refresh the prompt.
- IOLocker locker (m_output_mutex);
+ std::lock_guard<std::recursive_mutex> locker(m_output_mutex);
if (! IsGettingCommand())
return;
- // If we haven't finished writing the prompt, there's no need to refresh it.
+ // If we haven't finished writing the prompt, there's no need to refresh it.
if (m_expecting_prompt)
return;
@@ -562,7 +585,7 @@ IOChannel::OutWrite (const char *buffer, size_t len, bool asynchronous)
}
// Use the mutex to make sure OutWrite and ErrWrite do not interfere with each other's output.
- IOLocker locker (m_output_mutex);
+ std::lock_guard<std::recursive_mutex> locker(m_output_mutex);
if (m_driver->EditlineReaderIsTop() && asynchronous)
::fwrite (undo_prompt_string, 1, 4, m_out_file);
::fwrite (buffer, 1, len, m_out_file);
@@ -577,7 +600,7 @@ IOChannel::ErrWrite (const char *buffer, size_t len, bool asynchronous)
return;
// Use the mutex to make sure OutWrite and ErrWrite do not interfere with each other's output.
- IOLocker locker (m_output_mutex);
+ std::lock_guard<std::recursive_mutex> locker(m_output_mutex);
if (asynchronous)
::fwrite (undo_prompt_string, 1, 4, m_err_file);
::fwrite (buffer, 1, len, m_err_file);
@@ -631,17 +654,3 @@ IOChannel::SetGettingCommand (bool new_value)
{
m_getting_command = new_value;
}
-
-IOLocker::IOLocker (pthread_mutex_t &mutex) :
- m_mutex_ptr (&mutex)
-{
- if (m_mutex_ptr)
- ::pthread_mutex_lock (m_mutex_ptr);
-
-}
-
-IOLocker::~IOLocker ()
-{
- if (m_mutex_ptr)
- ::pthread_mutex_unlock (m_mutex_ptr);
-}