summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp')
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp114
1 files changed, 113 insertions, 1 deletions
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
index 652af4bdb7a..da04f46c25a 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
@@ -171,6 +171,12 @@ GDBRemoteCommunication::~GDBRemoteCommunication()
{
Disconnect();
}
+
+ // Stop the communications read thread which is used to parse all
+ // incoming packets. This function will block until the read
+ // thread returns.
+ if (m_read_thread_enabled)
+ StopReadThread();
}
char
@@ -295,7 +301,7 @@ GDBRemoteCommunication::PacketResult
GDBRemoteCommunication::GetAck ()
{
StringExtractorGDBRemote packet;
- PacketResult result = WaitForPacketWithTimeoutMicroSecondsNoLock (packet, GetPacketTimeoutInMicroSeconds (), false);
+ PacketResult result = ReadPacket (packet, GetPacketTimeoutInMicroSeconds (), false);
if (result == PacketResult::Success)
{
if (packet.GetResponseType() == StringExtractorGDBRemote::ResponseType::eAck)
@@ -324,6 +330,62 @@ GDBRemoteCommunication::WaitForNotRunningPrivate (const TimeValue *timeout_ptr)
}
GDBRemoteCommunication::PacketResult
+GDBRemoteCommunication::ReadPacket (StringExtractorGDBRemote &response, uint32_t timeout_usec, bool sync_on_timeout)
+{
+ if (m_read_thread_enabled)
+ return PopPacketFromQueue (response, timeout_usec);
+ else
+ return WaitForPacketWithTimeoutMicroSecondsNoLock (response, timeout_usec, sync_on_timeout);
+}
+
+
+// This function is called when a packet is requested.
+// A whole packet is popped from the packet queue and returned to the caller.
+// Packets are placed into this queue from the communication read thread.
+// See GDBRemoteCommunication::AppendBytesToCache.
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunication::PopPacketFromQueue (StringExtractorGDBRemote &response, uint32_t timeout_usec)
+{
+ // Calculate absolute timeout value
+ TimeValue timeout = TimeValue::Now();
+ timeout.OffsetWithMicroSeconds(timeout_usec);
+
+ do
+ {
+ // scope for the mutex
+ {
+ // lock down the packet queue
+ Mutex::Locker locker(m_packet_queue_mutex);
+
+ // Wait on condition variable.
+ if (m_packet_queue.size() == 0)
+ m_condition_queue_not_empty.Wait(m_packet_queue_mutex, &timeout);
+
+ if (m_packet_queue.size() > 0)
+ {
+ // get the front element of the queue
+ response = m_packet_queue.front();
+
+ // remove the front element
+ m_packet_queue.pop();
+
+ // we got a packet
+ return PacketResult::Success;
+ }
+ }
+
+ // Disconnected
+ if (!IsConnected())
+ return PacketResult::ErrorDisconnected;
+
+ // Loop while not timed out
+ } while (TimeValue::Now() < timeout);
+
+ return PacketResult::ErrorReplyTimeout;
+}
+
+
+GDBRemoteCommunication::PacketResult
GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractorGDBRemote &packet, uint32_t timeout_usec, bool sync_on_timeout)
{
uint8_t buffer[8192];
@@ -1094,3 +1156,53 @@ GDBRemoteCommunication::ScopedTimeout::~ScopedTimeout ()
{
m_gdb_comm.SetPacketTimeout (m_saved_timeout);
}
+
+// This function is called via the Communications class read thread when bytes become available
+// for this connection. This function will consume all incoming bytes and try to parse whole
+// packets as they become available. Full packets are placed in a queue, so that all packet
+// requests can simply pop from this queue. Async notification packets will be dispatched
+// immediately to the ProcessGDBRemote Async thread via an event.
+void GDBRemoteCommunication::AppendBytesToCache (const uint8_t * bytes, size_t len, bool broadcast, lldb::ConnectionStatus status)
+{
+ StringExtractorGDBRemote packet;
+
+ while (true)
+ {
+ PacketType type = CheckForPacket(bytes, len, packet);
+
+ // scrub the data so we do not pass it back to CheckForPacket
+ // on future passes of the loop
+ bytes = nullptr;
+ len = 0;
+
+ // we may have received no packet so lets bail out
+ if (type == PacketType::Invalid)
+ break;
+
+ if (type == PacketType::Standard)
+ {
+ // scope for the mutex
+ {
+ // lock down the packet queue
+ Mutex::Locker locker(m_packet_queue_mutex);
+ // push a new packet into the queue
+ m_packet_queue.push(packet);
+ // Signal condition variable that we have a packet
+ m_condition_queue_not_empty.Signal();
+
+ }
+ }
+
+ if (type == PacketType::Notify)
+ {
+ // put this packet into an event
+ const char *pdata = packet.GetStringRef().c_str();
+
+ // as the communication class, we are a broadcaster and the
+ // async thread is tuned to listen to us
+ BroadcastEvent(
+ eBroadcastBitGdbReadThreadGotNotify,
+ new EventDataBytes(pdata));
+ }
+ }
+}
OpenPOWER on IntegriCloud