blob: 9bf2b8e583fd16c84c012190de8dc2c3910585e7 [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 Ticebd13b8d2010-09-29 18:35:42 +000032#define NSEC_PER_USEC 1000ull
33#define USEC_PER_SEC 1000000ull
34#define NSEC_PER_SEC 1000000000ull
35
Chris Lattner30fdc8d2010-06-08 16:52:24 +000036static const char*
37el_prompt(EditLine *el)
38{
39 PromptMap::const_iterator pos = g_prompt_map.find (el);
40 if (pos == g_prompt_map.end())
41 return g_default_prompt;
42 return pos->second.c_str();
43}
44
45const char *
46IOChannel::GetPrompt ()
47{
48 PromptMap::const_iterator pos = g_prompt_map.find (m_edit_line);
49 if (pos == g_prompt_map.end())
50 return g_default_prompt;
51 return pos->second.c_str();
52}
53
54unsigned char
55IOChannel::ElCompletionFn (EditLine *e, int ch)
56{
57 IOChannel *io_channel;
58 if (el_get(e, EL_CLIENTDATA, &io_channel) == 0)
59 {
60 return io_channel->HandleCompletion (e, ch);
61 }
62 else
63 {
64 return CC_ERROR;
65 }
66}
67
68unsigned char
69IOChannel::HandleCompletion (EditLine *e, int ch)
70{
71 assert (e == m_edit_line);
72
73 const LineInfo *line_info = el_line(m_edit_line);
74 SBStringList completions;
Greg Claytonc982c762010-07-09 20:39:50 +000075 int page_size = 40;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000076
Greg Clayton66111032010-06-23 01:19:29 +000077 int num_completions = m_driver->GetDebugger().GetCommandInterpreter().HandleCompletion (line_info->buffer,
78 line_info->cursor,
79 line_info->lastchar,
80 0,
81 -1,
82 completions);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000083
84 if (num_completions == -1)
85 {
86 el_insertstr (m_edit_line, m_completion_key);
87 return CC_REDISPLAY;
88 }
89
90 // If we get a longer match display that first.
91 const char *completion_str = completions.GetStringAtIndex(0);
92 if (completion_str != NULL && *completion_str != '\0')
93 {
94 el_insertstr (m_edit_line, completion_str);
95 return CC_REDISPLAY;
96 }
97
98 if (num_completions > 1)
99 {
100 const char *comment = "\nAvailable completions:";
101
102 int num_elements = num_completions + 1;
103 OutWrite(comment, strlen (comment));
104 if (num_completions < page_size)
105 {
106 for (int i = 1; i < num_elements; i++)
107 {
Greg Claytonb1320972010-07-14 00:18:15 +0000108 completion_str = completions.GetStringAtIndex(i);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000109 OutWrite("\n\t", 2);
110 OutWrite(completion_str, strlen (completion_str));
111 }
112 OutWrite ("\n", 1);
113 }
114 else
115 {
116 int cur_pos = 1;
117 char reply;
118 int got_char;
119 while (cur_pos < num_elements)
120 {
121 int endpoint = cur_pos + page_size;
122 if (endpoint > num_elements)
123 endpoint = num_elements;
124 for (; cur_pos < endpoint; cur_pos++)
125 {
Greg Claytonb1320972010-07-14 00:18:15 +0000126 completion_str = completions.GetStringAtIndex(cur_pos);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000127 OutWrite("\n\t", 2);
128 OutWrite(completion_str, strlen (completion_str));
129 }
130
131 if (cur_pos >= num_elements)
132 {
133 OutWrite("\n", 1);
134 break;
135 }
136
137 OutWrite("\nMore (Y/n/a): ", strlen ("\nMore (Y/n/a): "));
138 reply = 'n';
139 got_char = el_getc(m_edit_line, &reply);
140 if (got_char == -1 || reply == 'n')
141 break;
142 if (reply == 'a')
143 page_size = num_elements - cur_pos;
144 }
145 }
146
147 }
148
149 if (num_completions == 0)
150 return CC_REFRESH_BEEP;
151 else
152 return CC_REDISPLAY;
153}
154
155IOChannel::IOChannel
156(
157 FILE *in,
158 FILE *out,
159 FILE *err,
160 Driver *driver
161) :
162 SBBroadcaster ("IOChannel"),
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000163 m_output_mutex (),
164 m_enter_elgets_time (),
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000165 m_driver (driver),
166 m_read_thread (LLDB_INVALID_HOST_THREAD),
167 m_read_thread_should_exit (false),
168 m_out_file (out),
169 m_err_file (err),
Greg Claytonc982c762010-07-09 20:39:50 +0000170 m_command_queue (),
171 m_completion_key ("\t"),
Johnny Chen23fd10c2010-08-27 22:35:26 +0000172 m_edit_line (::el_init (SBHostOS::GetProgramFileSpec().GetFilename(), in, out, err)),
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000173 m_history (history_init()),
Greg Claytonc982c762010-07-09 20:39:50 +0000174 m_history_event(),
175 m_getting_command (false)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000176{
177 assert (m_edit_line);
178 ::el_set (m_edit_line, EL_PROMPT, el_prompt);
179 ::el_set (m_edit_line, EL_EDITOR, "emacs");
180 ::el_set (m_edit_line, EL_HIST, history, m_history);
181
182 // Source $PWD/.editrc then $HOME/.editrc
183 ::el_source (m_edit_line, NULL);
184
185 el_set(m_edit_line, EL_ADDFN, "lldb_complete",
186 "LLDB completion function",
187 IOChannel::ElCompletionFn);
188 el_set(m_edit_line, EL_BIND, m_completion_key, "lldb_complete", NULL);
189 el_set (m_edit_line, EL_CLIENTDATA, this);
190
191 assert (m_history);
192 ::history (m_history, &m_history_event, H_SETSIZE, 800);
193 ::history (m_history, &m_history_event, H_SETUNIQUE, 1);
194 // Load history
195 HistorySaveLoad (false);
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000196
197 // Set up mutex to make sure OutErr, OutWrite and RefreshPrompt do not interfere
198 // with each other when writing.
199
200 int error;
201 ::pthread_mutexattr_t attr;
202 error = ::pthread_mutexattr_init (&attr);
203 assert (error == 0);
204 error = ::pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
205 assert (error == 0);
206 error = ::pthread_mutex_init (&m_output_mutex, &attr);
207 assert (error == 0);
208 error = ::pthread_mutexattr_destroy (&attr);
209 assert (error == 0);
210
211 // Initialize time that ::el_gets was last called.
212
213 m_enter_elgets_time.tv_sec = 0;
214 m_enter_elgets_time.tv_usec = 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000215}
216
217IOChannel::~IOChannel ()
218{
219 // Save history
220 HistorySaveLoad (true);
221
222 if (m_history != NULL)
223 {
224 ::history_end (m_history);
225 m_history = NULL;
226 }
227
228 if (m_edit_line != NULL)
229 {
230 ::el_end (m_edit_line);
231 m_edit_line = NULL;
232 }
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000233
234 ::pthread_mutex_destroy (&m_output_mutex);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000235}
236
237void
238IOChannel::HistorySaveLoad (bool save)
239{
240 if (m_history != NULL)
241 {
242 char history_path[PATH_MAX];
Johnny Chen23fd10c2010-08-27 22:35:26 +0000243 ::snprintf (history_path, sizeof(history_path), "~/.%s-history", SBHostOS::GetProgramFileSpec().GetFilename());
Greg Claytonc982c762010-07-09 20:39:50 +0000244 if ((size_t)SBFileSpec::ResolvePath (history_path, history_path, sizeof(history_path)) < sizeof(history_path) - 1)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000245 {
246 const char *path_ptr = history_path;
247 if (save)
248 ::history (m_history, &m_history_event, H_SAVE, path_ptr);
249 else
250 ::history (m_history, &m_history_event, H_LOAD, path_ptr);
251 }
252 }
253}
254
255bool
256IOChannel::LibeditGetInput (std::string &new_line)
257{
258 if (m_edit_line != NULL)
259 {
260 int line_len = 0;
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000261
262 // Set boolean indicating whether or not el_gets is trying to get input (i.e. whether or not to attempt
263 // to refresh the prompt after writing data).
264 SetGettingCommand (true);
265
266 // Get the current time just before calling el_gets; this is used by OutWrite, ErrWrite, and RefreshPrompt
267 // to make sure they have given el_gets enough time to write the prompt before they attempt to write
268 // anything.
269
270 ::gettimeofday (&m_enter_elgets_time, NULL);
271
272 // Call el_gets to prompt the user and read the user's input.
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000273 const char *line = ::el_gets (m_edit_line, &line_len);
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000274
275 // Re-set the boolean indicating whether or not el_gets is trying to get input.
276 SetGettingCommand (false);
277
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000278 if (line)
279 {
280 // strip any newlines off the end of the string...
281 while (line_len > 0 && (line[line_len - 1] == '\n' || line[line_len - 1] == '\r'))
282 --line_len;
283 if (line_len > 0)
284 {
285 ::history (m_history, &m_history_event, H_ENTER, line);
286 new_line.assign (line, line_len); // Omit the newline
287 }
288 else
289 {
290 // Someone just hit ENTER, return the empty string
291 new_line.clear();
292 }
293 // Return true to indicate success even if a string is empty
294 return true;
295 }
296 }
297 // Return false to indicate failure. This can happen when the file handle
298 // is closed (EOF).
299 new_line.clear();
300 return false;
301}
302
303void *
304IOChannel::IOReadThread (void *ptr)
305{
306 IOChannel *myself = static_cast<IOChannel *> (ptr);
307 myself->Run();
308 return NULL;
309}
310
311void
312IOChannel::Run ()
313{
314 SBListener listener("IOChannel::Run");
315 std::string new_line;
316
Greg Clayton66111032010-06-23 01:19:29 +0000317 SBBroadcaster interpreter_broadcaster (m_driver->GetDebugger().GetCommandInterpreter().GetBroadcaster());
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000318 listener.StartListeningForEvents (interpreter_broadcaster,
319 SBCommandInterpreter::eBroadcastBitResetPrompt |
320 SBCommandInterpreter::eBroadcastBitThreadShouldExit |
321 SBCommandInterpreter::eBroadcastBitQuitCommandReceived);
322
323 listener.StartListeningForEvents (*this,
324 IOChannel::eBroadcastBitThreadShouldExit);
325
326 listener.StartListeningForEvents (*m_driver,
327 Driver::eBroadcastBitReadyForInput |
328 Driver::eBroadcastBitThreadShouldExit);
329
330 // Let anyone know that the IO channel is up and listening and ready for events
331 BroadcastEventByType (eBroadcastBitThreadDidStart);
332 bool done = false;
333 while (!done)
334 {
335 SBEvent event;
336
337 listener.WaitForEvent (UINT32_MAX, event);
338 if (!event.IsValid())
339 continue;
340
341 const uint32_t event_type = event.GetType();
342
343 if (event.GetBroadcaster().IsValid())
344 {
345 if (event.BroadcasterMatchesPtr (m_driver))
346 {
347 if (event_type & Driver::eBroadcastBitReadyForInput)
348 {
349 std::string line;
350
351 if (CommandQueueIsEmpty())
352 {
353 if (LibeditGetInput(line) == false)
354 {
355 // EOF or some other file error occurred
356 done = true;
357 continue;
358 }
359 }
360 else
361 {
362 GetCommandFromQueue (line);
363 }
364
365 // TO BE DONE: FIGURE OUT WHICH COMMANDS SHOULD NOT BE REPEATED IF USER PRESSES PLAIN 'RETURN'
366 // AND TAKE CARE OF THAT HERE.
367
368 SBEvent line_event(IOChannel::eBroadcastBitHasUserInput,
369 line.c_str(),
370 line.size());
371 BroadcastEvent (line_event);
372 }
373 else if (event_type & Driver::eBroadcastBitThreadShouldExit)
374 {
375 done = true;
376 break;
377 }
378 }
379 else if (event.BroadcasterMatchesRef (interpreter_broadcaster))
380 {
381 switch (event_type)
382 {
383 case SBCommandInterpreter::eBroadcastBitResetPrompt:
384 {
385 const char *new_prompt = SBEvent::GetCStringFromEvent (event);
386 if (new_prompt)
387 g_prompt_map[m_edit_line] = new_prompt;
388 }
389 break;
390
391 case SBCommandInterpreter::eBroadcastBitThreadShouldExit:
392 case SBCommandInterpreter::eBroadcastBitQuitCommandReceived:
393 done = true;
394 break;
395 }
396 }
397 else if (event.BroadcasterMatchesPtr (this))
398 {
399 if (event_type & IOChannel::eBroadcastBitThreadShouldExit)
400 {
401 done = true;
402 break;
403 }
404 }
405 }
406 }
407 BroadcastEventByType (IOChannel::eBroadcastBitThreadDidExit);
408 m_driver = NULL;
409 m_read_thread = NULL;
410}
411
412bool
413IOChannel::Start ()
414{
Greg Clayton2da6d492011-02-08 01:34:25 +0000415 if (IS_VALID_LLDB_HOST_THREAD(m_read_thread))
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000416 return true;
417
418 m_read_thread = SBHostOS::ThreadCreate ("<lldb.driver.commandline_io>", IOChannel::IOReadThread, this,
419 NULL);
420
Greg Clayton2da6d492011-02-08 01:34:25 +0000421 return (IS_VALID_LLDB_HOST_THREAD(m_read_thread));
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000422}
423
424bool
425IOChannel::Stop ()
426{
Greg Clayton2da6d492011-02-08 01:34:25 +0000427 if (!IS_VALID_LLDB_HOST_THREAD(m_read_thread))
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000428 return true;
429
430 BroadcastEventByType (eBroadcastBitThreadShouldExit);
431
432 // Don't call Host::ThreadCancel since el_gets won't respond to this
433 // function call -- the thread will just die and all local variables in
434 // IOChannel::Run() won't get destructed down which is bad since there is
435 // a local listener holding onto broadcasters... To ensure proper shutdown,
436 // a ^D (control-D) sequence (0x04) should be written to other end of the
437 // the "in" file handle that was passed into the contructor as closing the
438 // file handle doesn't seem to make el_gets() exit....
439 return SBHostOS::ThreadJoin (m_read_thread, NULL, NULL);
440}
441
442void
443IOChannel::RefreshPrompt ()
444{
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000445 // If we are not in the middle of getting input from the user, there is no need to
446 // refresh the prompt.
447
448 if (! IsGettingCommand())
449 return;
450
Caroline Ticeefed6132010-11-19 20:47:54 +0000451 // Compare the current time versus the last time el_gets was called. If less than 40 milliseconds
452 // (40,0000 microseconds or 40,000,0000 nanoseconds) have elapsed, wait 40,0000 microseconds, to ensure el_gets had
453 // time to finish writing the prompt before we start writing here.
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000454
Caroline Ticeefed6132010-11-19 20:47:54 +0000455 if (ElapsedNanoSecondsSinceEnteringElGets() < (40 * 1000 * 1000))
456 usleep (40 * 1000);
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000457
458 // Use the mutex to make sure OutWrite, ErrWrite and Refresh prompt do not interfere with
459 // each other's output.
460
461 IOLocker locker (m_output_mutex);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000462 ::el_set (m_edit_line, EL_REFRESH);
463}
464
465void
466IOChannel::OutWrite (const char *buffer, size_t len)
467{
468 if (len == 0)
469 return;
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000470
471 // Compare the current time versus the last time el_gets was called. If less than
472 // 10000 microseconds (10000000 nanoseconds) have elapsed, wait 10000 microseconds, to ensure el_gets had time
473 // to finish writing the prompt before we start writing here.
474
475 if (ElapsedNanoSecondsSinceEnteringElGets() < 10000000)
476 usleep (10000);
477
478 {
479 // Use the mutex to make sure OutWrite, ErrWrite and Refresh prompt do not interfere with
480 // each other's output.
481 IOLocker locker (m_output_mutex);
482 ::fwrite (buffer, 1, len, m_out_file);
483 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000484}
485
486void
487IOChannel::ErrWrite (const char *buffer, size_t len)
488{
489 if (len == 0)
490 return;
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000491
492 // Compare the current time versus the last time el_gets was called. If less than
493 // 10000 microseconds (10000000 nanoseconds) have elapsed, wait 10000 microseconds, to ensure el_gets had time
494 // to finish writing the prompt before we start writing here.
495
496 if (ElapsedNanoSecondsSinceEnteringElGets() < 10000000)
497 usleep (10000);
498
499 {
500 // Use the mutex to make sure OutWrite, ErrWrite and Refresh prompt do not interfere with
501 // each other's output.
502 IOLocker locker (m_output_mutex);
503 ::fwrite (buffer, 1, len, m_err_file);
504 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000505}
506
507void
508IOChannel::AddCommandToQueue (const char *command)
509{
510 m_command_queue.push (std::string(command));
511}
512
513bool
514IOChannel::GetCommandFromQueue (std::string &cmd)
515{
516 if (m_command_queue.empty())
517 return false;
518 cmd.swap(m_command_queue.front());
519 m_command_queue.pop ();
520 return true;
521}
522
523int
524IOChannel::CommandQueueSize () const
525{
526 return m_command_queue.size();
527}
528
529void
530IOChannel::ClearCommandQueue ()
531{
532 while (!m_command_queue.empty())
533 m_command_queue.pop();
534}
535
536bool
537IOChannel::CommandQueueIsEmpty () const
538{
539 return m_command_queue.empty();
540}
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000541
542bool
543IOChannel::IsGettingCommand () const
544{
545 return m_getting_command;
546}
547
548void
549IOChannel::SetGettingCommand (bool new_value)
550{
551 m_getting_command = new_value;
552}
553
554uint64_t
555IOChannel::Nanoseconds (const struct timeval &time_val) const
556{
557 uint64_t nanoseconds = time_val.tv_sec * NSEC_PER_SEC + time_val.tv_usec * NSEC_PER_USEC;
558
559 return nanoseconds;
560}
561
562uint64_t
563IOChannel::ElapsedNanoSecondsSinceEnteringElGets ()
564{
565 if (! IsGettingCommand())
566 return 0;
567
568 struct timeval current_time;
569 ::gettimeofday (&current_time, NULL);
570 return (Nanoseconds (current_time) - Nanoseconds (m_enter_elgets_time));
571}
572
573IOLocker::IOLocker (pthread_mutex_t &mutex) :
574 m_mutex_ptr (&mutex)
575{
576 if (m_mutex_ptr)
577 ::pthread_mutex_lock (m_mutex_ptr);
578
579}
580
581IOLocker::~IOLocker ()
582{
583 if (m_mutex_ptr)
584 ::pthread_mutex_unlock (m_mutex_ptr);
585}