blob: f8de19810b14bbe0b1f4790bb253c0e7a44fc312 [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- Communication.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// C Includes
11// C++ Includes
12// Other libraries and framework includes
13// Project includes
14#include "lldb/lldb-private-log.h"
15#include "lldb/Core/Communication.h"
16#include "lldb/Core/Connection.h"
17#include "lldb/Core/Log.h"
18#include "lldb/Core/Timer.h"
19#include "lldb/Core/Event.h"
Eli Friedman88966972010-06-09 08:50:27 +000020#include <string.h>
Chris Lattner30fdc8d2010-06-08 16:52:24 +000021
22using namespace lldb;
23using namespace lldb_private;
24
25//----------------------------------------------------------------------
26// Constructor
27//----------------------------------------------------------------------
Caroline Tice82305fc2010-12-02 18:31:56 +000028Communication::Communication(const char *name, bool close_on_eof) :
Chris Lattner30fdc8d2010-06-08 16:52:24 +000029 Broadcaster (name),
30 m_connection_ap (),
Eli Friedman8878f872010-07-09 22:53:18 +000031 m_read_thread (LLDB_INVALID_HOST_THREAD),
Chris Lattner30fdc8d2010-06-08 16:52:24 +000032 m_read_thread_enabled (false),
33 m_bytes(),
34 m_bytes_mutex (Mutex::eMutexTypeRecursive),
35 m_callback (NULL),
Caroline Tice82305fc2010-12-02 18:31:56 +000036 m_callback_baton (NULL),
37 m_close_on_eof (close_on_eof)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000038
39{
40 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_OBJECT | LIBLLDB_LOG_COMMUNICATION,
41 "%p Communication::Communication (name = %s)",
42 this, name);
43}
44
45//----------------------------------------------------------------------
46// Destructor
47//----------------------------------------------------------------------
48Communication::~Communication()
49{
50 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_OBJECT | LIBLLDB_LOG_COMMUNICATION,
51 "%p Communication::~Communication (name = %s)",
52 this, m_broadcaster_name.AsCString(""));
53 Clear();
54}
55
56void
57Communication::Clear()
58{
59 StopReadThread (NULL);
60 Disconnect (NULL);
61}
62
63ConnectionStatus
64Communication::BytesAvailable (uint32_t timeout_usec, Error *error_ptr)
65{
66 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION, "%p Communication::BytesAvailable (timeout_usec = %u)", this, timeout_usec);
67
68 if (m_connection_ap.get())
69 return m_connection_ap->BytesAvailable (timeout_usec, error_ptr);
70 if (error_ptr)
71 error_ptr->SetErrorString("Invalid connection.");
72 return eConnectionStatusNoConnection;
73}
74
75ConnectionStatus
76Communication::Connect (const char *url, Error *error_ptr)
77{
78 Clear();
79
80 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION, "%p Communication::Connect (url = %s)", this, url);
81
82 if (m_connection_ap.get())
83 return m_connection_ap->Connect (url, error_ptr);
84 if (error_ptr)
85 error_ptr->SetErrorString("Invalid connection.");
86 return eConnectionStatusNoConnection;
87}
88
89ConnectionStatus
90Communication::Disconnect (Error *error_ptr)
91{
92 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION, "%p Communication::Disconnect ()", this);
93
94 if (m_connection_ap.get())
95 {
96 ConnectionStatus status = m_connection_ap->Disconnect (error_ptr);
97 m_connection_ap.reset();
98 return status;
99 }
100 return eConnectionStatusNoConnection;
101}
102
103bool
104Communication::IsConnected () const
105{
106 if (m_connection_ap.get())
107 return m_connection_ap->IsConnected ();
108 return false;
109}
110
111bool
112Communication::HasConnection () const
113{
114 return m_connection_ap.get() != NULL;
115}
116
117size_t
118Communication::Read (void *dst, size_t dst_len, uint32_t timeout_usec, ConnectionStatus &status, Error *error_ptr)
119{
120 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION,
121 "%p Communication::Write (dst = %p, dst_len = %zu, timeout_usec = %u) connection = %p",
122 this, dst, dst_len, timeout_usec, m_connection_ap.get());
123
Eli Friedman8878f872010-07-09 22:53:18 +0000124 if (m_read_thread != LLDB_INVALID_HOST_THREAD)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000125 {
126 // We have a dedicated read thread that is getting data for us
127 size_t cached_bytes = GetCachedBytes (dst, dst_len);
128 if (cached_bytes > 0 || timeout_usec == 0)
129 {
130 status = eConnectionStatusSuccess;
131 return cached_bytes;
132 }
133
134 if (m_connection_ap.get() == NULL)
135 {
136 if (error_ptr)
137 error_ptr->SetErrorString("Invalid connection.");
138 status = eConnectionStatusNoConnection;
139 return 0;
140 }
141 // Set the timeout appropriately
142 TimeValue timeout_time;
143 if (timeout_usec != UINT32_MAX)
144 {
145 timeout_time = TimeValue::Now();
146 timeout_time.OffsetWithMicroSeconds (timeout_usec);
147 }
148
149 Listener listener ("Communication::Read");
150 listener.StartListeningForEvents (this, eBroadcastBitReadThreadGotBytes | eBroadcastBitReadThreadDidExit);
151 EventSP event_sp;
152 while (listener.WaitForEvent (timeout_time.IsValid() ? &timeout_time : NULL, event_sp))
153 {
154 const uint32_t event_type = event_sp->GetType();
155 if (event_type & eBroadcastBitReadThreadGotBytes)
156 {
157 return GetCachedBytes (dst, dst_len);
158 }
159
160 if (event_type & eBroadcastBitReadThreadDidExit)
161 {
162 Disconnect (NULL);
163 break;
164 }
165 }
166 return 0;
167 }
168
169 // We aren't using a read thread, just read the data synchronously in this
170 // thread.
171 if (m_connection_ap.get())
172 {
173 status = m_connection_ap->BytesAvailable (timeout_usec, error_ptr);
174 if (status == eConnectionStatusSuccess)
175 return m_connection_ap->Read (dst, dst_len, status, error_ptr);
176 }
177
178 if (error_ptr)
179 error_ptr->SetErrorString("Invalid connection.");
180 status = eConnectionStatusNoConnection;
181 return 0;
182}
183
184
185size_t
186Communication::Write (const void *src, size_t src_len, ConnectionStatus &status, Error *error_ptr)
187{
188 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION,
189 "%p Communication::Write (src = %p, src_len = %zu) connection = %p",
190 this, src, src_len, m_connection_ap.get());
191
192 if (m_connection_ap.get())
193 return m_connection_ap->Write (src, src_len, status, error_ptr);
194
195 if (error_ptr)
196 error_ptr->SetErrorString("Invalid connection.");
197 status = eConnectionStatusNoConnection;
198 return 0;
199}
200
201
202bool
203Communication::StartReadThread (Error *error_ptr)
204{
205 if (m_read_thread != LLDB_INVALID_HOST_THREAD)
206 return true;
207
208 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION,
209 "%p Communication::StartReadThread ()", this);
210
211
212 char thread_name[1024];
213 snprintf(thread_name, sizeof(thread_name), "<lldb.comm.%s>", m_broadcaster_name.AsCString());
214
Greg Clayton86c3f342010-09-15 05:19:45 +0000215 m_read_thread_enabled = true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000216 m_read_thread = Host::ThreadCreate (thread_name, Communication::ReadThread, this, error_ptr);
Greg Clayton86c3f342010-09-15 05:19:45 +0000217 if (m_read_thread == LLDB_INVALID_HOST_THREAD)
218 m_read_thread_enabled = false;
Greg Clayton26661bc2010-07-23 15:43:25 +0000219 return m_read_thread_enabled;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000220}
221
222bool
223Communication::StopReadThread (Error *error_ptr)
224{
Eli Friedman8878f872010-07-09 22:53:18 +0000225 if (m_read_thread == LLDB_INVALID_HOST_THREAD)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000226 return true;
227
228 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION,
229 "%p Communication::StopReadThread ()", this);
230
231 m_read_thread_enabled = false;
232
233 BroadcastEvent (eBroadcastBitReadThreadShouldExit, NULL);
234
235 Host::ThreadCancel (m_read_thread, error_ptr);
236
237 return Host::ThreadJoin (m_read_thread, NULL, error_ptr);
Greg Clayton26661bc2010-07-23 15:43:25 +0000238 m_read_thread = LLDB_INVALID_HOST_THREAD;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000239}
240
241
242size_t
243Communication::GetCachedBytes (void *dst, size_t dst_len)
244{
245 Mutex::Locker locker(m_bytes_mutex);
246 if (m_bytes.size() > 0)
247 {
248 // If DST is NULL and we have a thread, then return the number
249 // of bytes that are available so the caller can call again
250 if (dst == NULL)
251 return m_bytes.size();
252
253 const size_t len = std::min<size_t>(dst_len, m_bytes.size());
254
Greg Clayton471b31c2010-07-20 22:52:08 +0000255 ::memcpy (dst, m_bytes.c_str(), len);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000256 m_bytes.erase(m_bytes.begin(), m_bytes.begin() + len);
257
258 return len;
259 }
260 return 0;
261}
262
263void
Caroline Ticeefed6132010-11-19 20:47:54 +0000264Communication::AppendBytesToCache (const uint8_t * bytes, size_t len, bool broadcast, ConnectionStatus status)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000265{
266 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION,
267 "%p Communication::AppendBytesToCache (src = %p, src_len = %zu, broadcast = %i)",
268 this, bytes, len, broadcast);
Caroline Tice82305fc2010-12-02 18:31:56 +0000269 if ((bytes == NULL || len == 0)
270 && (status != eConnectionStatusEndOfFile))
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000271 return;
272 if (m_callback)
273 {
274 // If the user registered a callback, then call it and do not broadcast
275 m_callback (m_callback_baton, bytes, len);
276 }
277 else
278 {
279 Mutex::Locker locker(m_bytes_mutex);
280 m_bytes.append ((const char *)bytes, len);
281 if (broadcast)
282 BroadcastEventIfUnique (eBroadcastBitReadThreadGotBytes);
283 }
284}
285
286size_t
287Communication::ReadFromConnection (void *dst, size_t dst_len, ConnectionStatus &status, Error *error_ptr)
288{
289 if (m_connection_ap.get())
290 return m_connection_ap->Read (dst, dst_len, status, error_ptr);
291 return 0;
292}
293
Caroline Tice82305fc2010-12-02 18:31:56 +0000294bool
295Communication::CloseOnEOF ()
296{
297 return m_close_on_eof;
298}
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000299
300bool
301Communication::ReadThreadIsRunning ()
302{
Eli Friedman8878f872010-07-09 22:53:18 +0000303 return m_read_thread != LLDB_INVALID_HOST_THREAD;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000304}
305
306void *
307Communication::ReadThread (void *p)
308{
309 Communication *comm = (Communication *)p;
310
Greg Clayton2d4edfb2010-11-06 01:53:30 +0000311 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_COMMUNICATION));
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000312
313 if (log)
314 log->Printf ("%p Communication::ReadThread () thread starting...", p);
315
316 uint8_t buf[1024];
317
318 Error error;
319 ConnectionStatus status = eConnectionStatusSuccess;
320 bool done = false;
321 while (!done && comm->m_read_thread_enabled)
322 {
323 status = comm->BytesAvailable (UINT32_MAX, &error);
324
325 if (status == eConnectionStatusSuccess)
326 {
327 size_t bytes_read = comm->ReadFromConnection (buf, sizeof(buf), status, &error);
328 if (bytes_read > 0)
Caroline Ticeefed6132010-11-19 20:47:54 +0000329 comm->AppendBytesToCache (buf, bytes_read, true, status);
Caroline Tice82305fc2010-12-02 18:31:56 +0000330 else if ((bytes_read == 0)
331 && status == eConnectionStatusEndOfFile)
332 {
333 if (comm->CloseOnEOF ())
334 comm->Disconnect ();
335 comm->AppendBytesToCache (buf, bytes_read, true, status);
336 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000337 }
338
339 switch (status)
340 {
341 case eConnectionStatusSuccess:
Caroline Tice82305fc2010-12-02 18:31:56 +0000342 case eConnectionStatusEndOfFile:
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000343 break;
344
345 case eConnectionStatusNoConnection: // No connection
346 case eConnectionStatusLostConnection: // Lost connection while connected to a valid connection
347 done = true;
348 // Fall through...
349 default:
350 case eConnectionStatusError: // Check GetError() for details
351 case eConnectionStatusTimedOut: // Request timed out
Greg Clayton2d4edfb2010-11-06 01:53:30 +0000352 if (log)
353 error.LogIfError(log.get(), "%p Communication::BytesAvailable () => status = %i", p, status);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000354 break;
355 }
356 }
Caroline Tice20ad3c42010-10-29 21:48:37 +0000357 log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_COMMUNICATION);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000358 if (log)
359 log->Printf ("%p Communication::ReadThread () thread exiting...", p);
360
361 // Let clients know that this thread is exiting
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000362 comm->BroadcastEvent (eBroadcastBitReadThreadDidExit);
363 return NULL;
364}
365
366void
367Communication::SetReadThreadBytesReceivedCallback
368(
369 ReadThreadBytesReceived callback,
370 void *callback_baton
371)
372{
373 m_callback = callback;
374 m_callback_baton = callback_baton;
375}
376
377void
378Communication::SetConnection (Connection *connection)
379{
380 StopReadThread(NULL);
381 Disconnect (NULL);
382 m_connection_ap.reset(connection);
383}
Caroline Ticeceb6b132010-10-26 03:11:13 +0000384
385const char *
386Communication::ConnectionStatusAsCString (lldb::ConnectionStatus status)
387{
388 switch (status)
389 {
390 case eConnectionStatusSuccess: return "success";
391 case eConnectionStatusError: return "error";
392 case eConnectionStatusTimedOut: return "timed out";
393 case eConnectionStatusNoConnection: return "no connection";
394 case eConnectionStatusLostConnection: return "lost connection";
395 }
396
397 static char unknown_state_string[64];
398 snprintf(unknown_state_string, sizeof (unknown_state_string), "ConnectionStatus = %i", status);
399 return unknown_state_string;
400}