Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -47,7 +47,8 @@ public: enum { - eBroadcastBitRunPacketSent = kLoUserBroadcastBit + eBroadcastBitRunPacketSent = kLoUserBroadcastBit, + eBroadcastBitGotNotify = kLoUserBroadcastBit << 1 // Sent when we received a notify packet. }; enum class PacketType @@ -111,7 +112,8 @@ PacketType CheckForPacket (const uint8_t *src, size_t src_len, - StringExtractorGDBRemote &packet); + StringExtractorGDBRemote &packet, + const bool peek = false); bool IsRunning() const { @@ -163,6 +165,9 @@ void DumpHistory(Stream &strm); + + GDBRemoteCommunication::PacketResult + PeekNotifyPacket(StringExtractorGDBRemote &packet); protected: @@ -319,6 +324,7 @@ private: HostThread m_listen_thread; std::string m_listen_url; + lldb_private::Mutex m_packet_read_mutex; //------------------------------------------------------------------ // For GDBRemoteCommunication only Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -324,16 +324,64 @@ } GDBRemoteCommunication::PacketResult +GDBRemoteCommunication::PeekNotifyPacket(StringExtractorGDBRemote &packet) +{ + Mutex::Locker locker(m_packet_read_mutex); + + // Check for a packet from our cache first without trying any reading... + if (CheckForPacket(NULL, 0, packet, true) == PacketType::Notify) + if (CheckForPacket(NULL, 0, packet) == PacketType::Notify) + return PacketResult::Success; + + lldb::ConnectionStatus status = eConnectionStatusNoConnection; + const uint32_t timeout_usec = 10 * 1000; // Wait for 10 ms for a response + uint8_t buffer[8192]; + Error error; + + size_t bytes_read = Read(buffer, sizeof(buffer), timeout_usec, status, &error); + + if (bytes_read > 0) + { + if (CheckForPacket(buffer, bytes_read, packet, true) == PacketType::Notify) + if (CheckForPacket(NULL, 0, packet) == PacketType::Notify) + return PacketResult::Success; + } + + return PacketResult::ErrorReplyFailed; +} + +GDBRemoteCommunication::PacketResult GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractorGDBRemote &packet, uint32_t timeout_usec, bool sync_on_timeout) { uint8_t buffer[8192]; Error error; + Mutex::Locker locker(m_packet_read_mutex); Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS | GDBR_LOG_VERBOSE)); // Check for a packet from our cache first without trying any reading... - if (CheckForPacket(NULL, 0, packet) != PacketType::Invalid) - return PacketResult::Success; + PacketType cache_type = CheckForPacket(NULL, 0, packet); + while (cache_type != PacketType::Invalid) + { + + if (cache_type == PacketType::Standard) + return PacketResult::Success; + else if (cache_type == PacketType::Notify) + { + // put this packet into an event + const char *pdata = packet.GetStringRef().c_str(); + lldb_private::EventDataBytes edata(pdata); + + // as the communication class, we are a broadcaster and the + // async thread is tuned to listen to us + BroadcastEvent( + eBroadcastBitGotNotify, + new EventDataBytes(pdata)); + + cache_type = CheckForPacket(NULL, 0, packet); + } + + } bool timed_out = false; bool disconnected = false; @@ -352,8 +400,28 @@ if (bytes_read > 0) { - if (CheckForPacket(buffer, bytes_read, packet) != PacketType::Invalid) - return PacketResult::Success; + PacketType type = CheckForPacket(buffer, bytes_read, packet); + while (type != PacketType::Invalid) + { + + if (type == PacketType::Standard) + return PacketResult::Success; + else if (type == PacketType::Notify) + { + // put this packet into an event + const char *pdata = packet.GetStringRef().c_str(); + lldb_private::EventDataBytes edata(pdata); + + // as the communication class, we are a broadcaster and the + // async thread is tuned to listen to us + BroadcastEvent( + eBroadcastBitGotNotify, + new EventDataBytes(pdata)); + + type = CheckForPacket(buffer, bytes_read, packet); + } + + } } else { @@ -485,7 +553,7 @@ } GDBRemoteCommunication::PacketType -GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, StringExtractorGDBRemote &packet) +GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, StringExtractorGDBRemote &packet, const bool peek) { // Put the packet data into the buffer in a thread safe fashion Mutex::Locker locker(m_bytes_mutex); @@ -585,7 +653,8 @@ if (log) log->Printf ("GDBRemoteCommunication::%s tossing %u junk bytes: '%.*s'", __FUNCTION__, idx - 1, idx - 1, m_bytes.c_str()); - m_bytes.erase(0, idx - 1); + if (!peek) + m_bytes.erase(0, idx - 1); } break; } @@ -730,7 +799,8 @@ } } - m_bytes.erase(0, total_length); + if (!peek) + m_bytes.erase(0, total_length); packet.SetFilePos(0); if (isNotifyPacket) Index: source/Plugins/Process/gdb-remote/ProcessGDBRemote.h =================================================================== --- source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -358,6 +358,9 @@ lldb::tid_t m_initial_tid; // The inital thread ID, given by stub on attach bool + HandleNotifyPacket (StringExtractorGDBRemote &packet); + + bool StartAsyncThread (); void Index: source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp =================================================================== --- source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -3223,6 +3223,34 @@ } +bool +ProcessGDBRemote::HandleNotifyPacket (StringExtractorGDBRemote &packet) +{ + // get the packet at a string + const std::string &pkt = packet.GetStringRef(); + // skip %stop: + StringExtractorGDBRemote stop_info(pkt.c_str() + 5); + + // pass as a thread stop info packet + SetLastStopPacket(stop_info); + + // check for more stop reasons + HandleStopReplySequence(); + + // if the process is stopped then we need to fake a resume + // so that we can stop properly with the new break + if (GetPrivateState() == lldb::StateType::eStateStopped) + { + SetPrivateState(lldb::StateType::eStateRunning); + } + + // since we have some stopped packets we can halt the process + SetPrivateState(lldb::StateType::eStateStopped); + + return true; +} + + thread_result_t ProcessGDBRemote::AsyncThread (void *arg) { @@ -3239,16 +3267,41 @@ if (listener.StartListeningForEvents (&process->m_async_broadcaster, desired_event_mask) == desired_event_mask) { - listener.StartListeningForEvents (&process->m_gdb_comm, Communication::eBroadcastBitReadThreadDidExit); + listener.StartListeningForEvents (&process->m_gdb_comm, GDBRemoteCommunication::eBroadcastBitGotNotify); + + TimeValue timeout_time; + const uint32_t timeout_usec = 500000; // Check for async notify after 0.5s bool done = false; while (!done) { + + StringExtractorGDBRemote notify; + if (process->m_gdb_comm.PeekNotifyPacket(notify) == GDBRemoteCommunication::PacketResult::Success) + process->HandleNotifyPacket(notify); + + timeout_time = TimeValue::Now(); + timeout_time.OffsetWithMicroSeconds(timeout_usec); + if (log) log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") listener.WaitForEvent (NULL, event_sp)...", __FUNCTION__, arg, process->GetID()); - if (listener.WaitForEvent (NULL, event_sp)) + if (listener.WaitForEvent (&timeout_time, event_sp)) { const uint32_t event_type = event_sp->GetType(); + + if (event_sp->BroadcasterIs (&process->m_gdb_comm)) + { + switch(event_type) + { + case GDBRemoteCommunication::eBroadcastBitGotNotify: + lldb_private::Event *event = event_sp.get(); + const EventDataBytes *continue_packet = EventDataBytes::GetEventDataFromEvent(event); + StringExtractorGDBRemote notify((const char*)continue_packet->GetBytes()); + process->HandleNotifyPacket(notify); + break; + } + } + if (event_sp->BroadcasterIs (&process->m_async_broadcaster)) { if (log) @@ -3353,7 +3406,6 @@ { if (log) log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") listener.WaitForEvent (NULL, event_sp) => false", __FUNCTION__, arg, process->GetID()); - done = true; } } }