Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp =================================================================== --- lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp +++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp @@ -60,7 +60,8 @@ std::chrono::seconds computed_timeout = std::min(interrupt_timeout, kWakeupInterval); for (;;) { - PacketResult read_result = ReadPacket(response, computed_timeout, false); + PacketResult read_result = + ReadPacket(response, computed_timeout, false, m_non_stop_protocol); // Reset the computed_timeout to the default value in case we are going // round again. computed_timeout = std::min(interrupt_timeout, kWakeupInterval); @@ -86,6 +87,7 @@ } break; } + case PacketResult::Notify: case PacketResult::Success: break; default: @@ -107,10 +109,11 @@ // 4) issue a "vCtrlC" command to ensure that all threads stop // 5) repeat 1-3 for the response to this packet - if (response.IsOKResponse()) + if (read_result == PacketResult::Success && m_non_stop_protocol && + response.IsOKResponse()) continue; - // TODO: get a proper mechanism for async notifications - if (response.GetStringRef().startswith("Stop:")) { + if (read_result == PacketResult::Notify && + response.GetStringRef().startswith("Stop:")) { response.Reset(response.GetStringRef().substr(5)); if (!DrainNotificationQueue("vStopped")) @@ -144,8 +147,8 @@ } // vCtrlC may not do anything, so timeout if we don't get notification - if (ReadPacket(stop_response, milliseconds(500), false) == - PacketResult::Success) { + if (ReadPacket(stop_response, milliseconds(500), false, true) == + PacketResult::Notify) { if (!stop_response.GetStringRef().startswith("Stop:")) { LLDB_LOGF(log, "GDBRemoteClientBase::%s () unexpected response " Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h =================================================================== --- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -12,6 +12,7 @@ #include "GDBRemoteCommunicationHistory.h" #include +#include #include #include #include @@ -89,17 +90,18 @@ enum class PacketType { Invalid = 0, Standard, Notify }; enum class PacketResult { - Success = 0, // Success - ErrorSendFailed, // Status sending the packet - ErrorSendAck, // Didn't get an ack back after sending a packet - ErrorReplyFailed, // Status getting the reply - ErrorReplyTimeout, // Timed out waiting for reply - ErrorReplyInvalid, // Got a reply but it wasn't valid for the packet that - // was sent - ErrorReplyAck, // Sending reply ack failed - ErrorDisconnected, // We were disconnected - ErrorNoSequenceLock // We couldn't get the sequence lock for a multi-packet - // request + Success = 0, // Success + ErrorSendFailed, // Status sending the packet + ErrorSendAck, // Didn't get an ack back after sending a packet + ErrorReplyFailed, // Status getting the reply + ErrorReplyTimeout, // Timed out waiting for reply + ErrorReplyInvalid, // Got a reply but it wasn't valid for the packet that + // was sent + ErrorReplyAck, // Sending reply ack failed + ErrorDisconnected, // We were disconnected + ErrorNoSequenceLock, // We couldn't get the sequence lock for a multi-packet + // request + Notify, // Successfully gotten a notification packet }; // Class to change the timeout for a given scope and restore it to the @@ -179,6 +181,7 @@ bool m_is_platform; // Set to true if this class represents a platform, // false if this class represents a debug session for // a single process + std::deque m_notification_packet_queue; CompressionType m_compression_type; @@ -190,7 +193,8 @@ bool skip_ack = false); PacketResult ReadPacket(StringExtractorGDBRemote &response, - Timeout timeout, bool sync_on_timeout); + Timeout timeout, bool sync_on_timeout, + bool allow_notification = false); PacketResult ReadPacketWithOutputSupport( StringExtractorGDBRemote &response, Timeout timeout, @@ -199,7 +203,8 @@ PacketResult WaitForPacketNoLock(StringExtractorGDBRemote &response, Timeout timeout, - bool sync_on_timeout); + bool sync_on_timeout, + bool allow_notification = false); bool CompressionIsEnabled() { return m_compression_type != CompressionType::None; Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp =================================================================== --- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -239,16 +239,15 @@ return result; } -GDBRemoteCommunication::PacketResult -GDBRemoteCommunication::ReadPacket(StringExtractorGDBRemote &response, - Timeout timeout, - bool sync_on_timeout) { +GDBRemoteCommunication::PacketResult GDBRemoteCommunication::ReadPacket( + StringExtractorGDBRemote &response, Timeout timeout, + bool sync_on_timeout, bool allow_notification) { using ResponseType = StringExtractorGDBRemote::ResponseType; Log *log = GetLog(GDBRLog::Packets); for (;;) { - PacketResult result = - WaitForPacketNoLock(response, timeout, sync_on_timeout); + PacketResult result = WaitForPacketNoLock( + response, timeout, sync_on_timeout, allow_notification); if (result != PacketResult::Success || (response.GetResponseType() != ResponseType::eAck && response.GetResponseType() != ResponseType::eNack)) @@ -260,15 +259,30 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunication::WaitForPacketNoLock(StringExtractorGDBRemote &packet, Timeout timeout, - bool sync_on_timeout) { + bool sync_on_timeout, + bool allow_notification) { uint8_t buffer[8192]; Status error; Log *log = GetLog(GDBRLog::Packets); - // Check for a packet from our cache first without trying any reading... - if (CheckForPacket(nullptr, 0, packet) != PacketType::Invalid) + // If the caller expects notifications, check the notification queue first. + if (allow_notification && !m_notification_packet_queue.empty()) { + packet.Reset(m_notification_packet_queue.front()); + m_notification_packet_queue.pop_front(); return PacketResult::Success; + } + + // Check for a packet from our cache first without trying any reading... + PacketType packet_type = CheckForPacket(nullptr, 0, packet); + if (packet_type == PacketType::Notify && !allow_notification) { + // If the caller does not support notifications, queue it for later. + m_notification_packet_queue.push_back(packet.GetStringRef().str()); + packet_type = CheckForPacket(nullptr, 0, packet); + } + if (packet_type != PacketType::Invalid) + return packet_type == PacketType::Standard ? PacketResult::Success + : PacketResult::Notify; bool timed_out = false; bool disconnected = false; @@ -283,8 +297,12 @@ bytes_read); if (bytes_read > 0) { - if (CheckForPacket(buffer, bytes_read, packet) != PacketType::Invalid) - return PacketResult::Success; + packet_type = CheckForPacket(buffer, bytes_read, packet); + if (packet_type == PacketType::Notify && !allow_notification) + m_notification_packet_queue.push_back(packet.GetStringRef().str()); + else if (packet_type != PacketType::Invalid) + return packet_type == PacketType::Standard ? PacketResult::Success + : PacketResult::Notify; } else { switch (status) { case eConnectionStatusTimedOut: @@ -1315,6 +1333,9 @@ case PacketResult::ErrorNoSequenceLock: Stream << "ErrorNoSequenceLock"; break; + case PacketResult::Notify: + Stream << "Notify"; + break; } }