Communication.cpp revision b89274fed17a85aeb81968685af781f24db30ded
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 <string.h> 21 22using namespace lldb; 23using namespace lldb_private; 24 25//---------------------------------------------------------------------- 26// Constructor 27//---------------------------------------------------------------------- 28Communication::Communication(const char *name) : 29 Broadcaster (name), 30 m_connection_ap (), 31 m_read_thread (LLDB_INVALID_HOST_THREAD), 32 m_read_thread_enabled (false), 33 m_bytes(), 34 m_bytes_mutex (Mutex::eMutexTypeRecursive), 35 m_callback (NULL), 36 m_callback_baton (NULL), 37 m_close_on_eof (true) 38 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 // We currently don't protect m_connection_ap with any mutex for 98 // multi-threaded environments. So lets not nuke our connection class 99 // without putting some multi-threaded protections in. We also probably 100 // don't want to pay for the overhead it might cause if every time we 101 // access the connection we have to take a lock. 102 // 103 // This auto_ptr will cleanup after itself when this object goes away, 104 // so there is no need to currently have it destroy itself immediately 105 // upon disconnnect. 106 //m_connection_ap.reset(); 107 return status; 108 } 109 return eConnectionStatusNoConnection; 110} 111 112bool 113Communication::IsConnected () const 114{ 115 if (m_connection_ap.get()) 116 return m_connection_ap->IsConnected (); 117 return false; 118} 119 120bool 121Communication::HasConnection () const 122{ 123 return m_connection_ap.get() != NULL; 124} 125 126size_t 127Communication::Read (void *dst, size_t dst_len, uint32_t timeout_usec, ConnectionStatus &status, Error *error_ptr) 128{ 129 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION, 130 "%p Communication::Write (dst = %p, dst_len = %zu, timeout_usec = %u) connection = %p", 131 this, dst, dst_len, timeout_usec, m_connection_ap.get()); 132 133 if (m_read_thread != LLDB_INVALID_HOST_THREAD) 134 { 135 // We have a dedicated read thread that is getting data for us 136 size_t cached_bytes = GetCachedBytes (dst, dst_len); 137 if (cached_bytes > 0 || timeout_usec == 0) 138 { 139 status = eConnectionStatusSuccess; 140 return cached_bytes; 141 } 142 143 if (m_connection_ap.get() == NULL) 144 { 145 if (error_ptr) 146 error_ptr->SetErrorString("Invalid connection."); 147 status = eConnectionStatusNoConnection; 148 return 0; 149 } 150 // Set the timeout appropriately 151 TimeValue timeout_time; 152 if (timeout_usec != UINT32_MAX) 153 { 154 timeout_time = TimeValue::Now(); 155 timeout_time.OffsetWithMicroSeconds (timeout_usec); 156 } 157 158 Listener listener ("Communication::Read"); 159 listener.StartListeningForEvents (this, eBroadcastBitReadThreadGotBytes | eBroadcastBitReadThreadDidExit); 160 EventSP event_sp; 161 while (listener.WaitForEvent (timeout_time.IsValid() ? &timeout_time : NULL, event_sp)) 162 { 163 const uint32_t event_type = event_sp->GetType(); 164 if (event_type & eBroadcastBitReadThreadGotBytes) 165 { 166 return GetCachedBytes (dst, dst_len); 167 } 168 169 if (event_type & eBroadcastBitReadThreadDidExit) 170 { 171 Disconnect (NULL); 172 break; 173 } 174 } 175 return 0; 176 } 177 178 // We aren't using a read thread, just read the data synchronously in this 179 // thread. 180 if (m_connection_ap.get()) 181 { 182 status = m_connection_ap->BytesAvailable (timeout_usec, error_ptr); 183 if (status == eConnectionStatusSuccess) 184 return m_connection_ap->Read (dst, dst_len, status, error_ptr); 185 } 186 187 if (error_ptr) 188 error_ptr->SetErrorString("Invalid connection."); 189 status = eConnectionStatusNoConnection; 190 return 0; 191} 192 193 194size_t 195Communication::Write (const void *src, size_t src_len, ConnectionStatus &status, Error *error_ptr) 196{ 197 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION, 198 "%p Communication::Write (src = %p, src_len = %zu) connection = %p", 199 this, src, src_len, m_connection_ap.get()); 200 201 if (m_connection_ap.get()) 202 return m_connection_ap->Write (src, src_len, status, error_ptr); 203 204 if (error_ptr) 205 error_ptr->SetErrorString("Invalid connection."); 206 status = eConnectionStatusNoConnection; 207 return 0; 208} 209 210 211bool 212Communication::StartReadThread (Error *error_ptr) 213{ 214 if (m_read_thread != LLDB_INVALID_HOST_THREAD) 215 return true; 216 217 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION, 218 "%p Communication::StartReadThread ()", this); 219 220 221 char thread_name[1024]; 222 snprintf(thread_name, sizeof(thread_name), "<lldb.comm.%s>", m_broadcaster_name.AsCString()); 223 224 m_read_thread_enabled = true; 225 m_read_thread = Host::ThreadCreate (thread_name, Communication::ReadThread, this, error_ptr); 226 if (m_read_thread == LLDB_INVALID_HOST_THREAD) 227 m_read_thread_enabled = false; 228 return m_read_thread_enabled; 229} 230 231bool 232Communication::StopReadThread (Error *error_ptr) 233{ 234 if (m_read_thread == LLDB_INVALID_HOST_THREAD) 235 return true; 236 237 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION, 238 "%p Communication::StopReadThread ()", this); 239 240 m_read_thread_enabled = false; 241 242 BroadcastEvent (eBroadcastBitReadThreadShouldExit, NULL); 243 244 Host::ThreadCancel (m_read_thread, error_ptr); 245 246 return Host::ThreadJoin (m_read_thread, NULL, error_ptr); 247 m_read_thread = LLDB_INVALID_HOST_THREAD; 248} 249 250 251size_t 252Communication::GetCachedBytes (void *dst, size_t dst_len) 253{ 254 Mutex::Locker locker(m_bytes_mutex); 255 if (m_bytes.size() > 0) 256 { 257 // If DST is NULL and we have a thread, then return the number 258 // of bytes that are available so the caller can call again 259 if (dst == NULL) 260 return m_bytes.size(); 261 262 const size_t len = std::min<size_t>(dst_len, m_bytes.size()); 263 264 ::memcpy (dst, m_bytes.c_str(), len); 265 m_bytes.erase(m_bytes.begin(), m_bytes.begin() + len); 266 267 return len; 268 } 269 return 0; 270} 271 272void 273Communication::AppendBytesToCache (const uint8_t * bytes, size_t len, bool broadcast, ConnectionStatus status) 274{ 275 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION, 276 "%p Communication::AppendBytesToCache (src = %p, src_len = %zu, broadcast = %i)", 277 this, bytes, len, broadcast); 278 if (bytes == NULL || len == 0) 279 return; 280 if (m_callback) 281 { 282 // If the user registered a callback, then call it and do not broadcast 283 m_callback (m_callback_baton, bytes, len); 284 } 285 else 286 { 287 Mutex::Locker locker(m_bytes_mutex); 288 m_bytes.append ((const char *)bytes, len); 289 if (broadcast) 290 BroadcastEventIfUnique (eBroadcastBitReadThreadGotBytes); 291 } 292} 293 294size_t 295Communication::ReadFromConnection (void *dst, size_t dst_len, ConnectionStatus &status, Error *error_ptr) 296{ 297 if (m_connection_ap.get()) 298 return m_connection_ap->Read (dst, dst_len, status, error_ptr); 299 return 0; 300} 301 302bool 303Communication::ReadThreadIsRunning () 304{ 305 return m_read_thread != LLDB_INVALID_HOST_THREAD; 306} 307 308void * 309Communication::ReadThread (void *p) 310{ 311 Communication *comm = (Communication *)p; 312 313 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_COMMUNICATION)); 314 315 if (log) 316 log->Printf ("%p Communication::ReadThread () thread starting...", p); 317 318 uint8_t buf[1024]; 319 320 Error error; 321 ConnectionStatus status = eConnectionStatusSuccess; 322 bool done = false; 323 while (!done && comm->m_read_thread_enabled) 324 { 325 status = comm->BytesAvailable (UINT32_MAX, &error); 326 327 if (status == eConnectionStatusSuccess) 328 { 329 size_t bytes_read = comm->ReadFromConnection (buf, sizeof(buf), status, &error); 330 if (bytes_read > 0) 331 comm->AppendBytesToCache (buf, bytes_read, true, status); 332 } 333 334 switch (status) 335 { 336 case eConnectionStatusSuccess: 337 break; 338 339 case eConnectionStatusEndOfFile: 340 case eConnectionStatusNoConnection: // No connection 341 case eConnectionStatusLostConnection: // Lost connection while connected to a valid connection 342 done = true; 343 // Fall through... 344 default: 345 case eConnectionStatusError: // Check GetError() for details 346 case eConnectionStatusTimedOut: // Request timed out 347 if (log) 348 error.LogIfError(log.get(), "%p Communication::BytesAvailable () => status = %i", p, status); 349 break; 350 } 351 } 352 log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_COMMUNICATION); 353 if (log) 354 log->Printf ("%p Communication::ReadThread () thread exiting...", p); 355 356 // Let clients know that this thread is exiting 357 comm->BroadcastEvent (eBroadcastBitReadThreadDidExit); 358 comm->m_read_thread = LLDB_INVALID_HOST_THREAD; 359 comm->Disconnect(); 360 return NULL; 361} 362 363void 364Communication::SetReadThreadBytesReceivedCallback 365( 366 ReadThreadBytesReceived callback, 367 void *callback_baton 368) 369{ 370 m_callback = callback; 371 m_callback_baton = callback_baton; 372} 373 374void 375Communication::SetConnection (Connection *connection) 376{ 377 StopReadThread(NULL); 378 Disconnect (NULL); 379 m_connection_ap.reset(connection); 380} 381 382const char * 383Communication::ConnectionStatusAsCString (lldb::ConnectionStatus status) 384{ 385 switch (status) 386 { 387 case eConnectionStatusSuccess: return "success"; 388 case eConnectionStatusError: return "error"; 389 case eConnectionStatusTimedOut: return "timed out"; 390 case eConnectionStatusNoConnection: return "no connection"; 391 case eConnectionStatusLostConnection: return "lost connection"; 392 } 393 394 static char unknown_state_string[64]; 395 snprintf(unknown_state_string, sizeof (unknown_state_string), "ConnectionStatus = %i", status); 396 return unknown_state_string; 397} 398