size_t Communication::Read (void *dst, size_t dst_len, uint32_t timeout_usec, ConnectionStatus &status, Error *error_ptr) { lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION, "%p Communication::Read (dst = %p, dst_len = %" PRIu64 ", timeout = %u usec) connection = %p", this, dst, (uint64_t)dst_len, timeout_usec, m_connection_sp.get()); if (m_read_thread_enabled) { // We have a dedicated read thread that is getting data for us size_t cached_bytes = GetCachedBytes (dst, dst_len); if (cached_bytes > 0 || timeout_usec == 0) { status = eConnectionStatusSuccess; return cached_bytes; } if (m_connection_sp.get() == NULL) { if (error_ptr) error_ptr->SetErrorString("Invalid connection."); status = eConnectionStatusNoConnection; return 0; } // Set the timeout appropriately TimeValue timeout_time; if (timeout_usec != UINT32_MAX) { timeout_time = TimeValue::Now(); timeout_time.OffsetWithMicroSeconds (timeout_usec); } Listener listener ("Communication::Read"); listener.StartListeningForEvents (this, eBroadcastBitReadThreadGotBytes | eBroadcastBitReadThreadDidExit); EventSP event_sp; while (listener.WaitForEvent (timeout_time.IsValid() ? &timeout_time : NULL, event_sp)) { const uint32_t event_type = event_sp->GetType(); if (event_type & eBroadcastBitReadThreadGotBytes) { return GetCachedBytes (dst, dst_len); } if (event_type & eBroadcastBitReadThreadDidExit) { Disconnect (NULL); break; } } return 0; } // We aren't using a read thread, just read the data synchronously in this // thread. lldb::ConnectionSP connection_sp (m_connection_sp); if (connection_sp.get()) { return connection_sp->Read (dst, dst_len, timeout_usec, status, error_ptr); } if (error_ptr) error_ptr->SetErrorString("Invalid connection."); status = eConnectionStatusNoConnection; return 0; }
void * ProcessKDP::AsyncThread (void *arg) { ProcessKDP *process = (ProcessKDP*) arg; const lldb::pid_t pid = process->GetID(); Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PROCESS)); if (log) log->Printf ("ProcessKDP::AsyncThread (arg = %p, pid = %" PRIu64 ") thread starting...", arg, pid); Listener listener ("ProcessKDP::AsyncThread"); EventSP event_sp; const uint32_t desired_event_mask = eBroadcastBitAsyncContinue | eBroadcastBitAsyncThreadShouldExit; if (listener.StartListeningForEvents (&process->m_async_broadcaster, desired_event_mask) == desired_event_mask) { bool done = false; while (!done) { if (log) log->Printf ("ProcessKDP::AsyncThread (pid = %" PRIu64 ") listener.WaitForEvent (NULL, event_sp)...", pid); if (listener.WaitForEvent (NULL, event_sp)) { uint32_t event_type = event_sp->GetType(); if (log) log->Printf ("ProcessKDP::AsyncThread (pid = %" PRIu64 ") Got an event of type: %d...", pid, event_type); // When we are running, poll for 1 second to try and get an exception // to indicate the process has stopped. If we don't get one, check to // make sure no one asked us to exit bool is_running = false; DataExtractor exc_reply_packet; do { switch (event_type) { case eBroadcastBitAsyncContinue: { is_running = true; if (process->m_comm.WaitForPacketWithTimeoutMicroSeconds (exc_reply_packet, 1 * USEC_PER_SEC)) { ThreadSP thread_sp (process->GetKernelThread()); if (thread_sp) { lldb::RegisterContextSP reg_ctx_sp (thread_sp->GetRegisterContext()); if (reg_ctx_sp) reg_ctx_sp->InvalidateAllRegisters(); static_cast<ThreadKDP *>(thread_sp.get())->SetStopInfoFrom_KDP_EXCEPTION (exc_reply_packet); } // TODO: parse the stop reply packet is_running = false; process->SetPrivateState(eStateStopped); } else { // Check to see if we are supposed to exit. There is no way to // interrupt a running kernel, so all we can do is wait for an // exception or detach... if (listener.GetNextEvent(event_sp)) { // We got an event, go through the loop again event_type = event_sp->GetType(); } } } break; case eBroadcastBitAsyncThreadShouldExit: if (log) log->Printf ("ProcessKDP::AsyncThread (pid = %" PRIu64 ") got eBroadcastBitAsyncThreadShouldExit...", pid); done = true; is_running = false; break; default: if (log) log->Printf ("ProcessKDP::AsyncThread (pid = %" PRIu64 ") got unknown event 0x%8.8x", pid, event_type); done = true; is_running = false; break; } } while (is_running); } else { if (log) log->Printf ("ProcessKDP::AsyncThread (pid = %" PRIu64 ") listener.WaitForEvent (NULL, event_sp) => false", pid); done = true; } } } if (log) log->Printf ("ProcessKDP::AsyncThread (arg = %p, pid = %" PRIu64 ") thread exiting...", arg, pid); process->m_async_thread.Reset(); return NULL; }