blob: 0ed6fd3267948119fa15196f01038ca675ddd6ef [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- IOChannel.cpp -------------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "IOChannel.h"
11
12#include <map>
13
Eli Friedmana382d472010-06-09 09:50:17 +000014#include "lldb/API/SBCommandInterpreter.h"
15#include "lldb/API/SBDebugger.h"
16#include "lldb/API/SBError.h"
17#include "lldb/API/SBEvent.h"
18#include "lldb/API/SBFileSpec.h"
19#include "lldb/API/SBHostOS.h"
20#include "lldb/API/SBListener.h"
21#include "lldb/API/SBStringList.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000022
Eli Friedman07b16272010-06-09 19:11:30 +000023#include <string.h>
24#include <limits.h>
25
Chris Lattner30fdc8d2010-06-08 16:52:24 +000026using namespace lldb;
27
28typedef std::map<EditLine *, std::string> PromptMap;
29const char *g_default_prompt = "(lldb) ";
30PromptMap g_prompt_map;
31
Caroline Ticefe1bdf22011-05-04 16:44:57 +000032// Printing the following string causes libedit to back up to the beginning of the line & blank it out.
33const char undo_prompt_string[4] = { (char) 13, (char) 27, (char) 91, (char) 75};
34
Chris Lattner30fdc8d2010-06-08 16:52:24 +000035static const char*
36el_prompt(EditLine *el)
37{
38 PromptMap::const_iterator pos = g_prompt_map.find (el);
39 if (pos == g_prompt_map.end())
40 return g_default_prompt;
41 return pos->second.c_str();
42}
43
44const char *
45IOChannel::GetPrompt ()
46{
47 PromptMap::const_iterator pos = g_prompt_map.find (m_edit_line);
48 if (pos == g_prompt_map.end())
49 return g_default_prompt;
50 return pos->second.c_str();
51}
52
Jim Ingham6d10c172012-06-01 01:03:40 +000053bool
54IOChannel::EditLineHasCharacters ()
55{
56 const LineInfo *line_info = el_line(m_edit_line);
57 if (line_info)
58 return line_info->cursor != line_info->buffer;
59 else
60 return false;
61}
62
63
Johnny Chenfd02a892012-05-09 21:03:07 +000064void
65IOChannel::EraseCharsBeforeCursor ()
66{
67 const LineInfo *line_info = el_line(m_edit_line);
68 el_deletestr(m_edit_line, line_info->cursor - line_info->buffer);
69}
70
Chris Lattner30fdc8d2010-06-08 16:52:24 +000071unsigned char
72IOChannel::ElCompletionFn (EditLine *e, int ch)
73{
74 IOChannel *io_channel;
75 if (el_get(e, EL_CLIENTDATA, &io_channel) == 0)
76 {
77 return io_channel->HandleCompletion (e, ch);
78 }
79 else
80 {
81 return CC_ERROR;
82 }
83}
84
85unsigned char
86IOChannel::HandleCompletion (EditLine *e, int ch)
87{
88 assert (e == m_edit_line);
89
90 const LineInfo *line_info = el_line(m_edit_line);
91 SBStringList completions;
Greg Claytonc982c762010-07-09 20:39:50 +000092 int page_size = 40;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000093
Greg Clayton66111032010-06-23 01:19:29 +000094 int num_completions = m_driver->GetDebugger().GetCommandInterpreter().HandleCompletion (line_info->buffer,
95 line_info->cursor,
96 line_info->lastchar,
97 0,
98 -1,
99 completions);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000100
101 if (num_completions == -1)
102 {
103 el_insertstr (m_edit_line, m_completion_key);
104 return CC_REDISPLAY;
105 }
Jim Inghama5a97eb2011-07-12 03:12:18 +0000106 else if (num_completions == -2)
107 {
108 el_deletestr (m_edit_line, line_info->cursor - line_info->buffer);
109 el_insertstr (m_edit_line, completions.GetStringAtIndex(0));
110 return CC_REDISPLAY;
111 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000112
113 // If we get a longer match display that first.
114 const char *completion_str = completions.GetStringAtIndex(0);
115 if (completion_str != NULL && *completion_str != '\0')
116 {
117 el_insertstr (m_edit_line, completion_str);
118 return CC_REDISPLAY;
119 }
120
121 if (num_completions > 1)
122 {
123 const char *comment = "\nAvailable completions:";
124
125 int num_elements = num_completions + 1;
Caroline Tice969ed3d2011-05-02 20:41:46 +0000126 OutWrite(comment, strlen (comment), NO_ASYNC);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000127 if (num_completions < page_size)
128 {
129 for (int i = 1; i < num_elements; i++)
130 {
Greg Claytonb1320972010-07-14 00:18:15 +0000131 completion_str = completions.GetStringAtIndex(i);
Caroline Tice969ed3d2011-05-02 20:41:46 +0000132 OutWrite("\n\t", 2, NO_ASYNC);
133 OutWrite(completion_str, strlen (completion_str), NO_ASYNC);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000134 }
Caroline Tice969ed3d2011-05-02 20:41:46 +0000135 OutWrite ("\n", 1, NO_ASYNC);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000136 }
137 else
138 {
139 int cur_pos = 1;
140 char reply;
141 int got_char;
142 while (cur_pos < num_elements)
143 {
144 int endpoint = cur_pos + page_size;
145 if (endpoint > num_elements)
146 endpoint = num_elements;
147 for (; cur_pos < endpoint; cur_pos++)
148 {
Greg Claytonb1320972010-07-14 00:18:15 +0000149 completion_str = completions.GetStringAtIndex(cur_pos);
Caroline Tice969ed3d2011-05-02 20:41:46 +0000150 OutWrite("\n\t", 2, NO_ASYNC);
151 OutWrite(completion_str, strlen (completion_str), NO_ASYNC);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000152 }
153
154 if (cur_pos >= num_elements)
155 {
Caroline Tice969ed3d2011-05-02 20:41:46 +0000156 OutWrite("\n", 1, NO_ASYNC);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000157 break;
158 }
159
Caroline Tice969ed3d2011-05-02 20:41:46 +0000160 OutWrite("\nMore (Y/n/a): ", strlen ("\nMore (Y/n/a): "), NO_ASYNC);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000161 reply = 'n';
162 got_char = el_getc(m_edit_line, &reply);
163 if (got_char == -1 || reply == 'n')
164 break;
165 if (reply == 'a')
166 page_size = num_elements - cur_pos;
167 }
168 }
169
170 }
171
172 if (num_completions == 0)
173 return CC_REFRESH_BEEP;
174 else
175 return CC_REDISPLAY;
176}
177
178IOChannel::IOChannel
179(
Caroline Tice969ed3d2011-05-02 20:41:46 +0000180 FILE *editline_in,
181 FILE *editline_out,
182 FILE *out,
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000183 FILE *err,
184 Driver *driver
185) :
186 SBBroadcaster ("IOChannel"),
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000187 m_output_mutex (),
188 m_enter_elgets_time (),
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000189 m_driver (driver),
190 m_read_thread (LLDB_INVALID_HOST_THREAD),
191 m_read_thread_should_exit (false),
192 m_out_file (out),
193 m_err_file (err),
Greg Claytonc982c762010-07-09 20:39:50 +0000194 m_command_queue (),
195 m_completion_key ("\t"),
Caroline Tice969ed3d2011-05-02 20:41:46 +0000196 m_edit_line (::el_init (SBHostOS::GetProgramFileSpec().GetFilename(), editline_in, editline_out, editline_out)),
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000197 m_history (history_init()),
Greg Claytonc982c762010-07-09 20:39:50 +0000198 m_history_event(),
Caroline Tice969ed3d2011-05-02 20:41:46 +0000199 m_getting_command (false),
200 m_expecting_prompt (false),
Caroline Tice86a73f92011-05-03 20:53:11 +0000201 m_prompt_str (),
202 m_refresh_request_pending (false)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000203{
204 assert (m_edit_line);
205 ::el_set (m_edit_line, EL_PROMPT, el_prompt);
206 ::el_set (m_edit_line, EL_EDITOR, "emacs");
207 ::el_set (m_edit_line, EL_HIST, history, m_history);
208
Caroline Tice0de8d452011-05-04 21:39:02 +0000209 el_set (m_edit_line, EL_ADDFN, "lldb_complete",
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000210 "LLDB completion function",
211 IOChannel::ElCompletionFn);
Caroline Tice0de8d452011-05-04 21:39:02 +0000212 el_set (m_edit_line, EL_BIND, m_completion_key, "lldb_complete", NULL);
213 el_set (m_edit_line, EL_BIND, "^r", "em-inc-search-prev", NULL); // Cycle through backwards search, entering string
Johnny Chen66b7c592012-05-05 04:44:12 +0000214 el_set (m_edit_line, EL_BIND, "^w", "ed-delete-prev-word", NULL); // Delete previous word, behave like bash does.
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000215 el_set (m_edit_line, EL_CLIENTDATA, this);
216
Johnny Chen5a4b4b82012-05-07 18:18:08 +0000217 // Source $PWD/.editrc then $HOME/.editrc
218 ::el_source (m_edit_line, NULL);
219
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000220 assert (m_history);
221 ::history (m_history, &m_history_event, H_SETSIZE, 800);
222 ::history (m_history, &m_history_event, H_SETUNIQUE, 1);
223 // Load history
224 HistorySaveLoad (false);
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000225
226 // Set up mutex to make sure OutErr, OutWrite and RefreshPrompt do not interfere
227 // with each other when writing.
228
229 int error;
230 ::pthread_mutexattr_t attr;
231 error = ::pthread_mutexattr_init (&attr);
232 assert (error == 0);
233 error = ::pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
234 assert (error == 0);
235 error = ::pthread_mutex_init (&m_output_mutex, &attr);
236 assert (error == 0);
237 error = ::pthread_mutexattr_destroy (&attr);
238 assert (error == 0);
239
240 // Initialize time that ::el_gets was last called.
241
242 m_enter_elgets_time.tv_sec = 0;
243 m_enter_elgets_time.tv_usec = 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000244}
245
246IOChannel::~IOChannel ()
247{
248 // Save history
249 HistorySaveLoad (true);
250
251 if (m_history != NULL)
252 {
253 ::history_end (m_history);
254 m_history = NULL;
255 }
256
257 if (m_edit_line != NULL)
258 {
259 ::el_end (m_edit_line);
260 m_edit_line = NULL;
261 }
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000262
263 ::pthread_mutex_destroy (&m_output_mutex);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000264}
265
266void
267IOChannel::HistorySaveLoad (bool save)
268{
269 if (m_history != NULL)
270 {
271 char history_path[PATH_MAX];
Johnny Chen23fd10c2010-08-27 22:35:26 +0000272 ::snprintf (history_path, sizeof(history_path), "~/.%s-history", SBHostOS::GetProgramFileSpec().GetFilename());
Greg Claytonc982c762010-07-09 20:39:50 +0000273 if ((size_t)SBFileSpec::ResolvePath (history_path, history_path, sizeof(history_path)) < sizeof(history_path) - 1)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000274 {
275 const char *path_ptr = history_path;
276 if (save)
277 ::history (m_history, &m_history_event, H_SAVE, path_ptr);
278 else
279 ::history (m_history, &m_history_event, H_LOAD, path_ptr);
280 }
281 }
282}
283
Caroline Tice969ed3d2011-05-02 20:41:46 +0000284void
285IOChannel::LibeditOutputBytesReceived (void *baton, const void *src, size_t src_len)
286{
287 // Make this a member variable.
288 // static std::string prompt_str;
289 IOChannel *io_channel = (IOChannel *) baton;
Caroline Tice86a73f92011-05-03 20:53:11 +0000290 IOLocker locker (io_channel->m_output_mutex);
Caroline Tice969ed3d2011-05-02 20:41:46 +0000291 const char *bytes = (const char *) src;
292
293 if (io_channel->IsGettingCommand() && io_channel->m_expecting_prompt)
294 {
295 io_channel->m_prompt_str.append (bytes, src_len);
296 // Log this to make sure the prompt is really what you think it is.
297 if (io_channel->m_prompt_str.find (el_prompt(io_channel->m_edit_line)) == 0)
298 {
299 io_channel->m_expecting_prompt = false;
Caroline Tice86a73f92011-05-03 20:53:11 +0000300 io_channel->m_refresh_request_pending = false;
Caroline Tice969ed3d2011-05-02 20:41:46 +0000301 io_channel->OutWrite (io_channel->m_prompt_str.c_str(),
302 io_channel->m_prompt_str.size(), NO_ASYNC);
303 io_channel->m_prompt_str.clear();
304 }
Caroline Tice969ed3d2011-05-02 20:41:46 +0000305 }
306 else
307 {
308 if (io_channel->m_prompt_str.size() > 0)
309 io_channel->m_prompt_str.clear();
Caroline Tice86a73f92011-05-03 20:53:11 +0000310 std::string tmp_str (bytes, src_len);
311 if (tmp_str.find (el_prompt (io_channel->m_edit_line)) == 0)
312 io_channel->m_refresh_request_pending = false;
Caroline Tice969ed3d2011-05-02 20:41:46 +0000313 io_channel->OutWrite (bytes, src_len, NO_ASYNC);
314 }
315}
316
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000317bool
318IOChannel::LibeditGetInput (std::string &new_line)
319{
320 if (m_edit_line != NULL)
321 {
322 int line_len = 0;
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000323
324 // Set boolean indicating whether or not el_gets is trying to get input (i.e. whether or not to attempt
325 // to refresh the prompt after writing data).
326 SetGettingCommand (true);
Caroline Tice969ed3d2011-05-02 20:41:46 +0000327 m_expecting_prompt = true;
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000328
329 // Call el_gets to prompt the user and read the user's input.
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000330 const char *line = ::el_gets (m_edit_line, &line_len);
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000331
332 // Re-set the boolean indicating whether or not el_gets is trying to get input.
333 SetGettingCommand (false);
334
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000335 if (line)
336 {
337 // strip any newlines off the end of the string...
338 while (line_len > 0 && (line[line_len - 1] == '\n' || line[line_len - 1] == '\r'))
339 --line_len;
340 if (line_len > 0)
341 {
342 ::history (m_history, &m_history_event, H_ENTER, line);
343 new_line.assign (line, line_len); // Omit the newline
344 }
345 else
346 {
347 // Someone just hit ENTER, return the empty string
348 new_line.clear();
349 }
350 // Return true to indicate success even if a string is empty
351 return true;
352 }
353 }
354 // Return false to indicate failure. This can happen when the file handle
355 // is closed (EOF).
356 new_line.clear();
357 return false;
358}
359
360void *
361IOChannel::IOReadThread (void *ptr)
362{
363 IOChannel *myself = static_cast<IOChannel *> (ptr);
364 myself->Run();
365 return NULL;
366}
367
368void
369IOChannel::Run ()
370{
371 SBListener listener("IOChannel::Run");
372 std::string new_line;
373
Greg Clayton66111032010-06-23 01:19:29 +0000374 SBBroadcaster interpreter_broadcaster (m_driver->GetDebugger().GetCommandInterpreter().GetBroadcaster());
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000375 listener.StartListeningForEvents (interpreter_broadcaster,
376 SBCommandInterpreter::eBroadcastBitResetPrompt |
377 SBCommandInterpreter::eBroadcastBitThreadShouldExit |
Caroline Tice86a73f92011-05-03 20:53:11 +0000378 SBCommandInterpreter::eBroadcastBitQuitCommandReceived);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000379
380 listener.StartListeningForEvents (*this,
381 IOChannel::eBroadcastBitThreadShouldExit);
382
383 listener.StartListeningForEvents (*m_driver,
384 Driver::eBroadcastBitReadyForInput |
385 Driver::eBroadcastBitThreadShouldExit);
386
387 // Let anyone know that the IO channel is up and listening and ready for events
388 BroadcastEventByType (eBroadcastBitThreadDidStart);
389 bool done = false;
390 while (!done)
391 {
392 SBEvent event;
393
394 listener.WaitForEvent (UINT32_MAX, event);
395 if (!event.IsValid())
396 continue;
397
398 const uint32_t event_type = event.GetType();
399
400 if (event.GetBroadcaster().IsValid())
401 {
402 if (event.BroadcasterMatchesPtr (m_driver))
403 {
404 if (event_type & Driver::eBroadcastBitReadyForInput)
405 {
406 std::string line;
407
408 if (CommandQueueIsEmpty())
409 {
410 if (LibeditGetInput(line) == false)
411 {
412 // EOF or some other file error occurred
413 done = true;
414 continue;
415 }
416 }
417 else
418 {
419 GetCommandFromQueue (line);
420 }
421
422 // TO BE DONE: FIGURE OUT WHICH COMMANDS SHOULD NOT BE REPEATED IF USER PRESSES PLAIN 'RETURN'
423 // AND TAKE CARE OF THAT HERE.
424
425 SBEvent line_event(IOChannel::eBroadcastBitHasUserInput,
426 line.c_str(),
427 line.size());
428 BroadcastEvent (line_event);
429 }
430 else if (event_type & Driver::eBroadcastBitThreadShouldExit)
431 {
432 done = true;
Johnny Chen25f3a3c2011-08-10 22:06:24 +0000433 continue;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000434 }
435 }
436 else if (event.BroadcasterMatchesRef (interpreter_broadcaster))
437 {
438 switch (event_type)
439 {
440 case SBCommandInterpreter::eBroadcastBitResetPrompt:
441 {
442 const char *new_prompt = SBEvent::GetCStringFromEvent (event);
443 if (new_prompt)
444 g_prompt_map[m_edit_line] = new_prompt;
445 }
446 break;
447
448 case SBCommandInterpreter::eBroadcastBitThreadShouldExit:
449 case SBCommandInterpreter::eBroadcastBitQuitCommandReceived:
450 done = true;
451 break;
452 }
453 }
454 else if (event.BroadcasterMatchesPtr (this))
455 {
456 if (event_type & IOChannel::eBroadcastBitThreadShouldExit)
457 {
458 done = true;
Johnny Chen25f3a3c2011-08-10 22:06:24 +0000459 continue;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000460 }
461 }
462 }
463 }
464 BroadcastEventByType (IOChannel::eBroadcastBitThreadDidExit);
465 m_driver = NULL;
466 m_read_thread = NULL;
467}
468
469bool
470IOChannel::Start ()
471{
Greg Clayton2da6d492011-02-08 01:34:25 +0000472 if (IS_VALID_LLDB_HOST_THREAD(m_read_thread))
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000473 return true;
474
475 m_read_thread = SBHostOS::ThreadCreate ("<lldb.driver.commandline_io>", IOChannel::IOReadThread, this,
476 NULL);
477
Greg Clayton2da6d492011-02-08 01:34:25 +0000478 return (IS_VALID_LLDB_HOST_THREAD(m_read_thread));
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000479}
480
481bool
482IOChannel::Stop ()
483{
Greg Clayton2da6d492011-02-08 01:34:25 +0000484 if (!IS_VALID_LLDB_HOST_THREAD(m_read_thread))
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000485 return true;
486
487 BroadcastEventByType (eBroadcastBitThreadShouldExit);
488
489 // Don't call Host::ThreadCancel since el_gets won't respond to this
490 // function call -- the thread will just die and all local variables in
491 // IOChannel::Run() won't get destructed down which is bad since there is
492 // a local listener holding onto broadcasters... To ensure proper shutdown,
493 // a ^D (control-D) sequence (0x04) should be written to other end of the
494 // the "in" file handle that was passed into the contructor as closing the
495 // file handle doesn't seem to make el_gets() exit....
496 return SBHostOS::ThreadJoin (m_read_thread, NULL, NULL);
497}
498
499void
500IOChannel::RefreshPrompt ()
501{
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000502 // If we are not in the middle of getting input from the user, there is no need to
503 // refresh the prompt.
Caroline Tice86a73f92011-05-03 20:53:11 +0000504 IOLocker locker (m_output_mutex);
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000505 if (! IsGettingCommand())
506 return;
507
Caroline Tice969ed3d2011-05-02 20:41:46 +0000508 // If we haven't finished writing the prompt, there's no need to refresh it.
509 if (m_expecting_prompt)
510 return;
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000511
Caroline Tice86a73f92011-05-03 20:53:11 +0000512 if (m_refresh_request_pending)
513 return;
514
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000515 ::el_set (m_edit_line, EL_REFRESH);
Caroline Tice86a73f92011-05-03 20:53:11 +0000516 m_refresh_request_pending = true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000517}
518
519void
Caroline Tice969ed3d2011-05-02 20:41:46 +0000520IOChannel::OutWrite (const char *buffer, size_t len, bool asynchronous)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000521{
522 if (len == 0)
523 return;
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000524
Jason Molenda7efc7e92011-08-12 02:40:17 +0000525 // We're in the process of exiting -- IOChannel::Run() has already completed
526 // and set m_driver to NULL - it is time for us to leave now. We might not
527 // print the final ^D to stdout in this case. We need to do some re-work on
528 // how the I/O streams are managed at some point.
529 if (m_driver == NULL)
530 {
531 return;
532 }
533
Caroline Tice969ed3d2011-05-02 20:41:46 +0000534 // Use the mutex to make sure OutWrite and ErrWrite do not interfere with each other's output.
535 IOLocker locker (m_output_mutex);
Caroline Tice9088b062011-05-09 23:06:58 +0000536 if (m_driver->EditlineReaderIsTop() && asynchronous)
Caroline Ticefe1bdf22011-05-04 16:44:57 +0000537 ::fwrite (undo_prompt_string, 1, 4, m_out_file);
Caroline Tice969ed3d2011-05-02 20:41:46 +0000538 ::fwrite (buffer, 1, len, m_out_file);
539 if (asynchronous)
540 m_driver->GetDebugger().NotifyTopInputReader (eInputReaderAsynchronousOutputWritten);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000541}
542
543void
Caroline Tice969ed3d2011-05-02 20:41:46 +0000544IOChannel::ErrWrite (const char *buffer, size_t len, bool asynchronous)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000545{
546 if (len == 0)
547 return;
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000548
Caroline Tice969ed3d2011-05-02 20:41:46 +0000549 // Use the mutex to make sure OutWrite and ErrWrite do not interfere with each other's output.
550 IOLocker locker (m_output_mutex);
551 if (asynchronous)
Caroline Ticefe1bdf22011-05-04 16:44:57 +0000552 ::fwrite (undo_prompt_string, 1, 4, m_err_file);
Caroline Tice969ed3d2011-05-02 20:41:46 +0000553 ::fwrite (buffer, 1, len, m_err_file);
554 if (asynchronous)
555 m_driver->GetDebugger().NotifyTopInputReader (eInputReaderAsynchronousOutputWritten);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000556}
557
558void
559IOChannel::AddCommandToQueue (const char *command)
560{
561 m_command_queue.push (std::string(command));
562}
563
564bool
565IOChannel::GetCommandFromQueue (std::string &cmd)
566{
567 if (m_command_queue.empty())
568 return false;
569 cmd.swap(m_command_queue.front());
570 m_command_queue.pop ();
571 return true;
572}
573
574int
575IOChannel::CommandQueueSize () const
576{
577 return m_command_queue.size();
578}
579
580void
581IOChannel::ClearCommandQueue ()
582{
583 while (!m_command_queue.empty())
584 m_command_queue.pop();
585}
586
587bool
588IOChannel::CommandQueueIsEmpty () const
589{
590 return m_command_queue.empty();
591}
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000592
593bool
594IOChannel::IsGettingCommand () const
595{
596 return m_getting_command;
597}
598
599void
600IOChannel::SetGettingCommand (bool new_value)
601{
602 m_getting_command = new_value;
603}
604
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000605IOLocker::IOLocker (pthread_mutex_t &mutex) :
606 m_mutex_ptr (&mutex)
607{
608 if (m_mutex_ptr)
609 ::pthread_mutex_lock (m_mutex_ptr);
610
611}
612
613IOLocker::~IOLocker ()
614{
615 if (m_mutex_ptr)
616 ::pthread_mutex_unlock (m_mutex_ptr);
617}