Communication.cpp revision 269024
1//===-- 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" 20#include "lldb/Host/Host.h" 21#include <string.h> 22 23using namespace lldb; 24using namespace lldb_private; 25 26ConstString & 27Communication::GetStaticBroadcasterClass () 28{ 29 static ConstString class_name ("lldb.communication"); 30 return class_name; 31} 32 33//---------------------------------------------------------------------- 34// Constructor 35//---------------------------------------------------------------------- 36Communication::Communication(const char *name) : 37 Broadcaster (NULL, name), 38 m_connection_sp (), 39 m_read_thread (LLDB_INVALID_HOST_THREAD), 40 m_read_thread_enabled (false), 41 m_bytes(), 42 m_bytes_mutex (Mutex::eMutexTypeRecursive), 43 m_write_mutex (Mutex::eMutexTypeNormal), 44 m_callback (NULL), 45 m_callback_baton (NULL), 46 m_close_on_eof (true) 47 48{ 49 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_OBJECT | LIBLLDB_LOG_COMMUNICATION, 50 "%p Communication::Communication (name = %s)", 51 this, name); 52 53 SetEventName (eBroadcastBitDisconnected, "disconnected"); 54 SetEventName (eBroadcastBitReadThreadGotBytes, "got bytes"); 55 SetEventName (eBroadcastBitReadThreadDidExit, "read thread did exit"); 56 SetEventName (eBroadcastBitReadThreadShouldExit, "read thread should exit"); 57 SetEventName (eBroadcastBitPacketAvailable, "packet available"); 58 59 CheckInWithManager(); 60} 61 62//---------------------------------------------------------------------- 63// Destructor 64//---------------------------------------------------------------------- 65Communication::~Communication() 66{ 67 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_OBJECT | LIBLLDB_LOG_COMMUNICATION, 68 "%p Communication::~Communication (name = %s)", 69 this, m_broadcaster_name.AsCString("")); 70 Clear(); 71} 72 73void 74Communication::Clear() 75{ 76 SetReadThreadBytesReceivedCallback (NULL, NULL); 77 Disconnect (NULL); 78 StopReadThread (NULL); 79} 80 81ConnectionStatus 82Communication::Connect (const char *url, Error *error_ptr) 83{ 84 Clear(); 85 86 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION, "%p Communication::Connect (url = %s)", this, url); 87 88 lldb::ConnectionSP connection_sp (m_connection_sp); 89 if (connection_sp.get()) 90 return connection_sp->Connect (url, error_ptr); 91 if (error_ptr) 92 error_ptr->SetErrorString("Invalid connection."); 93 return eConnectionStatusNoConnection; 94} 95 96ConnectionStatus 97Communication::Disconnect (Error *error_ptr) 98{ 99 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION, "%p Communication::Disconnect ()", this); 100 101 lldb::ConnectionSP connection_sp (m_connection_sp); 102 if (connection_sp.get()) 103 { 104 ConnectionStatus status = connection_sp->Disconnect (error_ptr); 105 // We currently don't protect connection_sp with any mutex for 106 // multi-threaded environments. So lets not nuke our connection class 107 // without putting some multi-threaded protections in. We also probably 108 // don't want to pay for the overhead it might cause if every time we 109 // access the connection we have to take a lock. 110 // 111 // This unique pointer will cleanup after itself when this object goes away, 112 // so there is no need to currently have it destroy itself immediately 113 // upon disconnnect. 114 //connection_sp.reset(); 115 return status; 116 } 117 return eConnectionStatusNoConnection; 118} 119 120bool 121Communication::IsConnected () const 122{ 123 lldb::ConnectionSP connection_sp (m_connection_sp); 124 if (connection_sp.get()) 125 return connection_sp->IsConnected (); 126 return false; 127} 128 129bool 130Communication::HasConnection () const 131{ 132 return m_connection_sp.get() != NULL; 133} 134 135size_t 136Communication::Read (void *dst, size_t dst_len, uint32_t timeout_usec, ConnectionStatus &status, Error *error_ptr) 137{ 138 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION, 139 "%p Communication::Read (dst = %p, dst_len = %" PRIu64 ", timeout = %u usec) connection = %p", 140 this, 141 dst, 142 (uint64_t)dst_len, 143 timeout_usec, 144 m_connection_sp.get()); 145 146 if (m_read_thread_enabled) 147 { 148 // We have a dedicated read thread that is getting data for us 149 size_t cached_bytes = GetCachedBytes (dst, dst_len); 150 if (cached_bytes > 0 || timeout_usec == 0) 151 { 152 status = eConnectionStatusSuccess; 153 return cached_bytes; 154 } 155 156 if (m_connection_sp.get() == NULL) 157 { 158 if (error_ptr) 159 error_ptr->SetErrorString("Invalid connection."); 160 status = eConnectionStatusNoConnection; 161 return 0; 162 } 163 // Set the timeout appropriately 164 TimeValue timeout_time; 165 if (timeout_usec != UINT32_MAX) 166 { 167 timeout_time = TimeValue::Now(); 168 timeout_time.OffsetWithMicroSeconds (timeout_usec); 169 } 170 171 Listener listener ("Communication::Read"); 172 listener.StartListeningForEvents (this, eBroadcastBitReadThreadGotBytes | eBroadcastBitReadThreadDidExit); 173 EventSP event_sp; 174 while (listener.WaitForEvent (timeout_time.IsValid() ? &timeout_time : NULL, event_sp)) 175 { 176 const uint32_t event_type = event_sp->GetType(); 177 if (event_type & eBroadcastBitReadThreadGotBytes) 178 { 179 return GetCachedBytes (dst, dst_len); 180 } 181 182 if (event_type & eBroadcastBitReadThreadDidExit) 183 { 184 Disconnect (NULL); 185 break; 186 } 187 } 188 return 0; 189 } 190 191 // We aren't using a read thread, just read the data synchronously in this 192 // thread. 193 lldb::ConnectionSP connection_sp (m_connection_sp); 194 if (connection_sp.get()) 195 { 196 return connection_sp->Read (dst, dst_len, timeout_usec, status, error_ptr); 197 } 198 199 if (error_ptr) 200 error_ptr->SetErrorString("Invalid connection."); 201 status = eConnectionStatusNoConnection; 202 return 0; 203} 204 205 206size_t 207Communication::Write (const void *src, size_t src_len, ConnectionStatus &status, Error *error_ptr) 208{ 209 lldb::ConnectionSP connection_sp (m_connection_sp); 210 211 Mutex::Locker locker(m_write_mutex); 212 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION, 213 "%p Communication::Write (src = %p, src_len = %" PRIu64 ") connection = %p", 214 this, 215 src, 216 (uint64_t)src_len, 217 connection_sp.get()); 218 219 if (connection_sp.get()) 220 return connection_sp->Write (src, src_len, status, error_ptr); 221 222 if (error_ptr) 223 error_ptr->SetErrorString("Invalid connection."); 224 status = eConnectionStatusNoConnection; 225 return 0; 226} 227 228 229bool 230Communication::StartReadThread (Error *error_ptr) 231{ 232 if (error_ptr) 233 error_ptr->Clear(); 234 235 if (IS_VALID_LLDB_HOST_THREAD(m_read_thread)) 236 return true; 237 238 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION, 239 "%p Communication::StartReadThread ()", this); 240 241 242 char thread_name[1024]; 243 snprintf(thread_name, sizeof(thread_name), "<lldb.comm.%s>", m_broadcaster_name.AsCString()); 244 245 m_read_thread_enabled = true; 246 m_read_thread = Host::ThreadCreate (thread_name, Communication::ReadThread, this, error_ptr); 247 if (!IS_VALID_LLDB_HOST_THREAD(m_read_thread)) 248 m_read_thread_enabled = false; 249 return m_read_thread_enabled; 250} 251 252bool 253Communication::StopReadThread (Error *error_ptr) 254{ 255 if (!IS_VALID_LLDB_HOST_THREAD(m_read_thread)) 256 return true; 257 258 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION, 259 "%p Communication::StopReadThread ()", this); 260 261 m_read_thread_enabled = false; 262 263 BroadcastEvent (eBroadcastBitReadThreadShouldExit, NULL); 264 265 //Host::ThreadCancel (m_read_thread, error_ptr); 266 267 bool status = Host::ThreadJoin (m_read_thread, NULL, error_ptr); 268 m_read_thread = LLDB_INVALID_HOST_THREAD; 269 return status; 270} 271 272bool 273Communication::JoinReadThread (Error *error_ptr) 274{ 275 if (!IS_VALID_LLDB_HOST_THREAD(m_read_thread)) 276 return true; 277 278 bool success = Host::ThreadJoin (m_read_thread, NULL, error_ptr); 279 m_read_thread = LLDB_INVALID_HOST_THREAD; 280 return success; 281} 282 283size_t 284Communication::GetCachedBytes (void *dst, size_t dst_len) 285{ 286 Mutex::Locker locker(m_bytes_mutex); 287 if (m_bytes.size() > 0) 288 { 289 // If DST is NULL and we have a thread, then return the number 290 // of bytes that are available so the caller can call again 291 if (dst == NULL) 292 return m_bytes.size(); 293 294 const size_t len = std::min<size_t>(dst_len, m_bytes.size()); 295 296 ::memcpy (dst, m_bytes.c_str(), len); 297 m_bytes.erase(m_bytes.begin(), m_bytes.begin() + len); 298 299 return len; 300 } 301 return 0; 302} 303 304void 305Communication::AppendBytesToCache (const uint8_t * bytes, size_t len, bool broadcast, ConnectionStatus status) 306{ 307 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION, 308 "%p Communication::AppendBytesToCache (src = %p, src_len = %" PRIu64 ", broadcast = %i)", 309 this, bytes, (uint64_t)len, broadcast); 310 if ((bytes == NULL || len == 0) 311 && (status != lldb::eConnectionStatusEndOfFile)) 312 return; 313 if (m_callback) 314 { 315 // If the user registered a callback, then call it and do not broadcast 316 m_callback (m_callback_baton, bytes, len); 317 } 318 else if (bytes != NULL && len > 0) 319 { 320 Mutex::Locker locker(m_bytes_mutex); 321 m_bytes.append ((const char *)bytes, len); 322 if (broadcast) 323 BroadcastEventIfUnique (eBroadcastBitReadThreadGotBytes); 324 } 325} 326 327size_t 328Communication::ReadFromConnection (void *dst, 329 size_t dst_len, 330 uint32_t timeout_usec, 331 ConnectionStatus &status, 332 Error *error_ptr) 333{ 334 lldb::ConnectionSP connection_sp (m_connection_sp); 335 if (connection_sp.get()) 336 return connection_sp->Read (dst, dst_len, timeout_usec, status, error_ptr); 337 return 0; 338} 339 340bool 341Communication::ReadThreadIsRunning () 342{ 343 return m_read_thread_enabled; 344} 345 346lldb::thread_result_t 347Communication::ReadThread (lldb::thread_arg_t p) 348{ 349 Communication *comm = (Communication *)p; 350 351 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_COMMUNICATION)); 352 353 if (log) 354 log->Printf ("%p Communication::ReadThread () thread starting...", p); 355 356 uint8_t buf[1024]; 357 358 Error error; 359 ConnectionStatus status = eConnectionStatusSuccess; 360 bool done = false; 361 while (!done && comm->m_read_thread_enabled) 362 { 363 size_t bytes_read = comm->ReadFromConnection (buf, sizeof(buf), 5 * TimeValue::MicroSecPerSec, status, &error); 364 if (bytes_read > 0) 365 comm->AppendBytesToCache (buf, bytes_read, true, status); 366 else if ((bytes_read == 0) 367 && status == eConnectionStatusEndOfFile) 368 { 369 if (comm->GetCloseOnEOF ()) 370 comm->Disconnect (); 371 comm->AppendBytesToCache (buf, bytes_read, true, status); 372 } 373 374 switch (status) 375 { 376 case eConnectionStatusSuccess: 377 break; 378 379 case eConnectionStatusEndOfFile: 380 if (comm->GetCloseOnEOF()) 381 done = true; 382 break; 383 case eConnectionStatusNoConnection: // No connection 384 case eConnectionStatusLostConnection: // Lost connection while connected to a valid connection 385 done = true; 386 // Fall through... 387 case eConnectionStatusError: // Check GetError() for details 388 case eConnectionStatusTimedOut: // Request timed out 389 if (log) 390 error.LogIfError (log, 391 "%p Communication::ReadFromConnection () => status = %s", 392 p, 393 Communication::ConnectionStatusAsCString (status)); 394 break; 395 } 396 } 397 log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_COMMUNICATION); 398 if (log) 399 log->Printf ("%p Communication::ReadThread () thread exiting...", p); 400 401 // Let clients know that this thread is exiting 402 comm->BroadcastEvent (eBroadcastBitReadThreadDidExit); 403 return NULL; 404} 405 406void 407Communication::SetReadThreadBytesReceivedCallback 408( 409 ReadThreadBytesReceived callback, 410 void *callback_baton 411) 412{ 413 m_callback = callback; 414 m_callback_baton = callback_baton; 415} 416 417void 418Communication::SetConnection (Connection *connection) 419{ 420 Disconnect (NULL); 421 StopReadThread(NULL); 422 m_connection_sp.reset(connection); 423} 424 425const char * 426Communication::ConnectionStatusAsCString (lldb::ConnectionStatus status) 427{ 428 switch (status) 429 { 430 case eConnectionStatusSuccess: return "success"; 431 case eConnectionStatusError: return "error"; 432 case eConnectionStatusTimedOut: return "timed out"; 433 case eConnectionStatusNoConnection: return "no connection"; 434 case eConnectionStatusLostConnection: return "lost connection"; 435 case eConnectionStatusEndOfFile: return "end of file"; 436 } 437 438 static char unknown_state_string[64]; 439 snprintf(unknown_state_string, sizeof (unknown_state_string), "ConnectionStatus = %i", status); 440 return unknown_state_string; 441} 442