blob: 9258a0cd4039db1cc5c2210a27ee8c194698bda0 [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);
Greg Clayton7788e5f2010-12-04 02:22:36 +0000269 if (bytes == NULL || len == 0)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000270 return;
271 if (m_callback)
272 {
273 // If the user registered a callback, then call it and do not broadcast
274 m_callback (m_callback_baton, bytes, len);
275 }
276 else
277 {
278 Mutex::Locker locker(m_bytes_mutex);
279 m_bytes.append ((const char *)bytes, len);
280 if (broadcast)
281 BroadcastEventIfUnique (eBroadcastBitReadThreadGotBytes);
282 }
283}
284
285size_t
286Communication::ReadFromConnection (void *dst, size_t dst_len, ConnectionStatus &status, Error *error_ptr)
287{
288 if (m_connection_ap.get())
289 return m_connection_ap->Read (dst, dst_len, status, error_ptr);
290 return 0;
291}
292
Caroline Tice82305fc2010-12-02 18:31:56 +0000293bool
294Communication::CloseOnEOF ()
295{
296 return m_close_on_eof;
297}
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000298
299bool
300Communication::ReadThreadIsRunning ()
301{
Eli Friedman8878f872010-07-09 22:53:18 +0000302 return m_read_thread != LLDB_INVALID_HOST_THREAD;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000303}
304
305void *
306Communication::ReadThread (void *p)
307{
308 Communication *comm = (Communication *)p;
309
Greg Clayton2d4edfb2010-11-06 01:53:30 +0000310 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_COMMUNICATION));
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000311
312 if (log)
313 log->Printf ("%p Communication::ReadThread () thread starting...", p);
314
315 uint8_t buf[1024];
316
317 Error error;
318 ConnectionStatus status = eConnectionStatusSuccess;
319 bool done = false;
320 while (!done && comm->m_read_thread_enabled)
321 {
322 status = comm->BytesAvailable (UINT32_MAX, &error);
323
324 if (status == eConnectionStatusSuccess)
325 {
326 size_t bytes_read = comm->ReadFromConnection (buf, sizeof(buf), status, &error);
327 if (bytes_read > 0)
Caroline Ticeefed6132010-11-19 20:47:54 +0000328 comm->AppendBytesToCache (buf, bytes_read, true, status);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000329 }
330
331 switch (status)
332 {
333 case eConnectionStatusSuccess:
334 break;
335
Greg Clayton7788e5f2010-12-04 02:22:36 +0000336 case eConnectionStatusEndOfFile:
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000337 case eConnectionStatusNoConnection: // No connection
338 case eConnectionStatusLostConnection: // Lost connection while connected to a valid connection
339 done = true;
340 // Fall through...
341 default:
342 case eConnectionStatusError: // Check GetError() for details
343 case eConnectionStatusTimedOut: // Request timed out
Greg Clayton2d4edfb2010-11-06 01:53:30 +0000344 if (log)
345 error.LogIfError(log.get(), "%p Communication::BytesAvailable () => status = %i", p, status);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000346 break;
347 }
348 }
Caroline Tice20ad3c42010-10-29 21:48:37 +0000349 log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_COMMUNICATION);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000350 if (log)
351 log->Printf ("%p Communication::ReadThread () thread exiting...", p);
352
353 // Let clients know that this thread is exiting
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000354 comm->BroadcastEvent (eBroadcastBitReadThreadDidExit);
355 return NULL;
356}
357
358void
359Communication::SetReadThreadBytesReceivedCallback
360(
361 ReadThreadBytesReceived callback,
362 void *callback_baton
363)
364{
365 m_callback = callback;
366 m_callback_baton = callback_baton;
367}
368
369void
370Communication::SetConnection (Connection *connection)
371{
372 StopReadThread(NULL);
373 Disconnect (NULL);
374 m_connection_ap.reset(connection);
375}
Caroline Ticeceb6b132010-10-26 03:11:13 +0000376
377const char *
378Communication::ConnectionStatusAsCString (lldb::ConnectionStatus status)
379{
380 switch (status)
381 {
382 case eConnectionStatusSuccess: return "success";
383 case eConnectionStatusError: return "error";
384 case eConnectionStatusTimedOut: return "timed out";
385 case eConnectionStatusNoConnection: return "no connection";
386 case eConnectionStatusLostConnection: return "lost connection";
387 }
388
389 static char unknown_state_string[64];
390 snprintf(unknown_state_string, sizeof (unknown_state_string), "ConnectionStatus = %i", status);
391 return unknown_state_string;
392}