labath updated this revision to Diff 67507.
labath added a comment.
The patch I used to run the tests. Still very much WIP.
https://reviews.llvm.org/D22914
Files:
source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp
source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h
source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
unittests/Process/gdb-remote/GDBRemoteClientBaseTest.cpp
Index: unittests/Process/gdb-remote/GDBRemoteClientBaseTest.cpp
===================================================================
--- unittests/Process/gdb-remote/GDBRemoteClientBaseTest.cpp
+++ unittests/Process/gdb-remote/GDBRemoteClientBaseTest.cpp
@@ -235,6 +235,7 @@
{
StringExtractorGDBRemote continue_response, async_response, response;
const bool send_async = true;
+ const GDBRemoteClientBase::Lock::Kind send_kind = GDBRemoteClientBase::Lock::Exclusive;
ContinueFixture fix;
if (HasFailure())
return;
@@ -247,10 +248,11 @@
fix.WaitForRunEvent();
// Sending without async enabled should fail.
- ASSERT_EQ(PacketResult::ErrorSendFailed, fix.client.SendPacketAndWaitForResponse("qTest1", response, !send_async));
+ ASSERT_EQ(PacketResult::ErrorSendFailed,
+ fix.client.SendPacketAndWaitForResponse("qTest1", response, send_kind, !send_async));
std::future<PacketResult> async_result = std::async(std::launch::async, [&] {
- return fix.client.SendPacketAndWaitForResponse("qTest2", async_response, send_async);
+ return fix.client.SendPacketAndWaitForResponse("qTest2", async_response, send_kind, send_async);
});
// First we'll get interrupted.
@@ -341,6 +343,7 @@
{
StringExtractorGDBRemote continue_response, async_response, response;
const bool send_async = true;
+ const GDBRemoteClientBase::Lock::Kind send_kind = GDBRemoteClientBase::Lock::Exclusive;
ContinueFixture fix;
if (HasFailure())
return;
@@ -370,7 +373,7 @@
// Packet stream should remain synchronized.
std::future<PacketResult> send_result = std::async(std::launch::async, [&] {
- return fix.client.SendPacketAndWaitForResponse("qTest", async_response, !send_async);
+ return fix.client.SendPacketAndWaitForResponse("qTest", async_response, send_kind, !send_async);
});
ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
ASSERT_EQ("qTest", response.GetStringRef());
@@ -426,3 +429,81 @@
ASSERT_TRUE(async_result.get());
ASSERT_EQ(eStateInvalid, continue_state.get());
}
+
+TEST(GDBRemoteClientBaseTest, SendTwoPacketsInterleaved)
+{
+ StringExtractorGDBRemote async_response1, async_response2, response1, response2;
+ const GDBRemoteClientBase::Lock::Kind send_kind = GDBRemoteClientBase::Lock::Shared;
+ ContinueFixture fix;
+ if (HasFailure())
+ return;
+
+ std::future<PacketResult> async_result1 = std::async(std::launch::async, [&] {
+ return fix.client.SendPacketAndWaitForResponse("qTest1", async_response1, send_kind);
+ });
+
+ std::future<PacketResult> async_result2 = std::async(std::launch::async, [&] {
+ return fix.client.SendPacketAndWaitForResponse("qTest2", async_response2, send_kind);
+ });
+
+ // Make sure we can get both requests before we send out the response. The order in which
+ // they come is non-deterministic.
+ ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response1));
+ ASSERT_TRUE(response1.GetStringRef() == "qTest1" || response1.GetStringRef() == "qTest2");
+ ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response2));
+ ASSERT_TRUE(response2.GetStringRef() == "qTest1" || response2.GetStringRef() == "qTest2");
+ ASSERT_NE(response1.GetStringRef(), response2.GetStringRef());
+
+ // Send both responses (in the correct order).
+ ASSERT_EQ(PacketResult::Success, fix.server.SendPacket(response1.GetStringRef() + "X"));
+ ASSERT_EQ(PacketResult::Success, fix.server.SendPacket(response2.GetStringRef() + "X"));
+
+ // And make sure they get received.
+ ASSERT_EQ(PacketResult::Success, async_result1.get());
+ ASSERT_EQ("qTest1X", async_response1.GetStringRef());
+ ASSERT_EQ(PacketResult::Success, async_result2.get());
+ ASSERT_EQ("qTest2X", async_response2.GetStringRef());
+}
+
+TEST(GDBRemoteClientBaseTest, SendManyPacketsStress)
+{
+ StringExtractorGDBRemote async_response1, async_response2, response1, response2;
+ const GDBRemoteClientBase::Lock::Kind send_kind = GDBRemoteClientBase::Lock::Shared;
+ ContinueFixture fix;
+ if (HasFailure())
+ return;
+
+ // Fire up the senders.
+ std::vector<std::thread> packet_threads;
+ for (unsigned i = 0; i < 4; ++i)
+ {
+ packet_threads.emplace_back([i, &fix] {
+ std::ostringstream packet;
+ packet << "qTest" << i;
+ StringExtractorGDBRemote response;
+ for (unsigned j = 0; j < 10; ++j)
+ {
+ ASSERT_EQ(PacketResult::Success,
+ fix.client.SendPacketAndWaitForResponse(packet.str(), response, send_kind));
+ ASSERT_EQ(packet.str(), response.GetStringRef());
+ }
+ });
+ }
+
+ // Our "server" will just mirror the packets back at the senders.
+ std::thread mirror_thread([&] {
+ PacketResult result;
+ StringExtractorGDBRemote packet;
+ while ((result = fix.server.GetPacket(packet)) == PacketResult::Success)
+ ASSERT_EQ(PacketResult::Success, fix.server.SendPacket(packet.GetStringRef()));
+ ASSERT_EQ(PacketResult::ErrorDisconnected, result);
+ });
+
+ // Let the senders finish.
+ for (std::thread &t : packet_threads)
+ t.join();
+
+ // Close the client connection so the server thread can exit.
+ fix.client.Disconnect();
+ mirror_thread.join();
+}
Index: source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
===================================================================
--- source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -528,7 +528,8 @@
const int packet_len = ::snprintf (packet, sizeof(packet), "qRegisterInfo%x", reg_num);
assert (packet_len < (int)sizeof(packet));
StringExtractorGDBRemote response;
- if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success)
+ if (m_gdb_comm.SendPacketAndWaitForResponse(llvm::StringRef(packet, packet_len), response) ==
+ GDBRemoteCommunication::PacketResult::Success)
{
response_type = response.GetResponseType();
if (response_type == StringExtractorGDBRemote::eResponse)
@@ -1163,7 +1164,7 @@
for (size_t idx = 0; idx < num_cmds; idx++)
{
StringExtractorGDBRemote response;
- m_gdb_comm.SendPacketAndWaitForResponse (GetExtraStartupCommands().GetArgumentAtIndex(idx), response, false);
+ m_gdb_comm.SendPacketAndWaitForResponse(GetExtraStartupCommands().GetArgumentAtIndex(idx), response);
}
return error;
}
@@ -1647,7 +1648,7 @@
{
// Send vStopped
StringExtractorGDBRemote response;
- m_gdb_comm.SendPacketAndWaitForResponse("vStopped", response, false);
+ m_gdb_comm.SendPacketAndWaitForResponse("vStopped", response);
// OK represents end of signal list
if (response.IsOKResponse())
@@ -5030,7 +5031,8 @@
packet.PutCStringAsRawHex8(file_path.c_str());
StringExtractorGDBRemote response;
- if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), response, false) != GDBRemoteCommunication::PacketResult::Success)
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response) !=
+ GDBRemoteCommunication::PacketResult::Success)
return Error("Sending qFileLoadAddress packet failed");
if (response.IsErrorResponse())
@@ -5405,7 +5407,8 @@
const char *packet_cstr = command.GetArgumentAtIndex(0);
bool send_async = true;
StringExtractorGDBRemote response;
- process->GetGDBRemote().SendPacketAndWaitForResponse(packet_cstr, response, send_async);
+ process->GetGDBRemote().SendPacketAndWaitForResponse(packet_cstr, response,
+ GDBRemoteClientBase::Lock::Exclusive, send_async);
result.SetStatus (eReturnStatusSuccessFinishResult);
Stream &output_strm = result.GetOutputStream();
output_strm.Printf (" packet: %s\n", packet_cstr);
@@ -5464,7 +5467,8 @@
bool send_async = true;
StringExtractorGDBRemote response;
- process->GetGDBRemote().SendPacketAndWaitForResponse(packet_cstr, response, send_async);
+ process->GetGDBRemote().SendPacketAndWaitForResponse(packet_cstr, response,
+ GDBRemoteClientBase::Lock::Exclusive, send_async);
result.SetStatus (eReturnStatusSuccessFinishResult);
Stream &output_strm = result.GetOutputStream();
output_strm.Printf (" packet: %s\n", packet_cstr);
Index: source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
===================================================================
--- source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
+++ source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
@@ -403,8 +403,7 @@
reg_info->byte_size, // dst length
m_reg_data.GetByteOrder())) // dst byte order
{
- GDBRemoteClientBase::Lock lock(gdb_comm, false);
- if (lock)
+ if (true)
{
const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported();
ProcessSP process_sp (m_thread.GetProcess());
@@ -572,8 +571,7 @@
const bool use_g_packet = gdb_comm.AvoidGPackets ((ProcessGDBRemote *)process) == false;
- GDBRemoteClientBase::Lock lock(gdb_comm, false);
- if (lock)
+ if (true)
{
SyncThreadState(process);
@@ -681,8 +679,7 @@
const bool use_g_packet = gdb_comm.AvoidGPackets ((ProcessGDBRemote *)process) == false;
StringExtractorGDBRemote response;
- GDBRemoteClientBase::Lock lock(gdb_comm, false);
- if (lock)
+ if (true)
{
const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported();
ProcessSP process_sp (m_thread.GetProcess());
Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
===================================================================
--- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -253,7 +253,7 @@
GDBRemoteCommunication::ScopedTimeout timeout (*this, std::max (old_timeout, minimum_timeout));
StringExtractorGDBRemote response;
- if (SendPacketAndWaitForResponse("QStartNoAckMode", response, false) == PacketResult::Success)
+ if (SendPacketAndWaitForResponse("QStartNoAckMode", response) == PacketResult::Success)
{
if (response.IsOKResponse())
{
@@ -274,7 +274,7 @@
m_supports_threads_in_stop_reply = eLazyBoolNo;
StringExtractorGDBRemote response;
- if (SendPacketAndWaitForResponse("QListThreadsInStopReply", response, false) == PacketResult::Success)
+ if (SendPacketAndWaitForResponse("QListThreadsInStopReply", response) == PacketResult::Success)
{
if (response.IsOKResponse())
m_supports_threads_in_stop_reply = eLazyBoolYes;
@@ -290,7 +290,7 @@
m_attach_or_wait_reply = eLazyBoolNo;
StringExtractorGDBRemote response;
- if (SendPacketAndWaitForResponse("qVAttachOrWaitSupported", response, false) == PacketResult::Success)
+ if (SendPacketAndWaitForResponse("qVAttachOrWaitSupported", response) == PacketResult::Success)
{
if (response.IsOKResponse())
m_attach_or_wait_reply = eLazyBoolYes;
@@ -310,7 +310,7 @@
m_prepare_for_reg_writing_reply = eLazyBoolNo;
StringExtractorGDBRemote response;
- if (SendPacketAndWaitForResponse("qSyncThreadStateSupported", response, false) == PacketResult::Success)
+ if (SendPacketAndWaitForResponse("qSyncThreadStateSupported", response) == PacketResult::Success)
{
if (response.IsOKResponse())
m_prepare_for_reg_writing_reply = eLazyBoolYes;
@@ -408,9 +408,7 @@
}
StringExtractorGDBRemote response;
- if (SendPacketAndWaitForResponse(packet.GetData(),
- response,
- /*send_async=*/false) == PacketResult::Success)
+ if (SendPacketAndWaitForResponse(packet.GetData(), response) == PacketResult::Success)
{
const char *response_cstr = response.GetStringRef().c_str();
if (::strstr (response_cstr, "qXfer:auxv:read+"))
@@ -508,7 +506,7 @@
{
StringExtractorGDBRemote response;
m_supports_thread_suffix = eLazyBoolNo;
- if (SendPacketAndWaitForResponse("QThreadSuffixSupported", response, false) == PacketResult::Success)
+ if (SendPacketAndWaitForResponse("QThreadSuffixSupported", response) == PacketResult::Success)
{
if (response.IsOKResponse())
m_supports_thread_suffix = eLazyBoolYes;
@@ -528,7 +526,7 @@
m_supports_vCont_C = eLazyBoolNo;
m_supports_vCont_s = eLazyBoolNo;
m_supports_vCont_S = eLazyBoolNo;
- if (SendPacketAndWaitForResponse("vCont?", response, false) == PacketResult::Success)
+ if (SendPacketAndWaitForResponse("vCont?", response) == PacketResult::Success)
{
const char *response_cstr = response.GetStringRef().c_str();
if (::strstr (response_cstr, ";c"))
@@ -591,8 +589,8 @@
snprintf(packet, sizeof(packet), "p0;thread:%" PRIx64 ";", tid);
else
snprintf(packet, sizeof(packet), "p0");
-
- if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success)
+
+ if (SendPacketAndWaitForResponse(packet, response) == PacketResult::Success)
{
if (response.IsNormalResponse())
m_supports_p = eLazyBoolYes;
@@ -611,7 +609,7 @@
{
StringExtractorGDBRemote response;
response.SetResponseValidatorToJSON();
- if (SendPacketAndWaitForResponse("jThreadsInfo", response, false) == PacketResult::Success)
+ if (SendPacketAndWaitForResponse("jThreadsInfo", response) == PacketResult::Success)
{
if (response.IsUnsupportedResponse())
{
@@ -634,7 +632,7 @@
{
StringExtractorGDBRemote response;
m_supports_jThreadExtendedInfo = eLazyBoolNo;
- if (SendPacketAndWaitForResponse("jThreadExtendedInfo:", response, false) == PacketResult::Success)
+ if (SendPacketAndWaitForResponse("jThreadExtendedInfo:", response) == PacketResult::Success)
{
if (response.IsOKResponse())
{
@@ -652,7 +650,7 @@
{
StringExtractorGDBRemote response;
m_supports_jLoadedDynamicLibrariesInfos = eLazyBoolNo;
- if (SendPacketAndWaitForResponse("jGetLoadedDynamicLibrariesInfos:", response, false) == PacketResult::Success)
+ if (SendPacketAndWaitForResponse("jGetLoadedDynamicLibrariesInfos:", response) == PacketResult::Success)
{
if (response.IsOKResponse())
{
@@ -670,7 +668,7 @@
{
StringExtractorGDBRemote response;
m_supports_jGetSharedCacheInfo = eLazyBoolNo;
- if (SendPacketAndWaitForResponse("jGetSharedCacheInfo:", response, false) == PacketResult::Success)
+ if (SendPacketAndWaitForResponse("jGetSharedCacheInfo:", response) == PacketResult::Success)
{
if (response.IsOKResponse())
{
@@ -690,7 +688,7 @@
m_supports_x = eLazyBoolNo;
char packet[256];
snprintf (packet, sizeof (packet), "x0,0");
- if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success)
+ if (SendPacketAndWaitForResponse(packet, response) == PacketResult::Success)
{
if (response.IsOKResponse())
m_supports_x = eLazyBoolYes;
@@ -706,7 +704,7 @@
std::string &response_string
)
{
- Lock lock(*this, false);
+ Lock lock(*this);
if (!lock)
{
Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS | GDBR_LOG_PACKETS));
@@ -1097,7 +1095,7 @@
m_qGDBServerVersion_is_valid = eLazyBoolNo;
StringExtractorGDBRemote response;
- if (SendPacketAndWaitForResponse ("qGDBServerVersion", response, false) == PacketResult::Success)
+ if (SendPacketAndWaitForResponse("qGDBServerVersion", response) == PacketResult::Success)
{
if (response.IsNormalResponse())
{
@@ -1221,7 +1219,7 @@
{
StringExtractorGDBRemote response;
std::string packet = "QEnableCompression:type:" + avail_name + ";";
- if (SendPacketAndWaitForResponse (packet.c_str(), response, false) != PacketResult::Success)
+ if (SendPacketAndWaitForResponse(packet, response) != PacketResult::Success)
return;
if (response.IsOKResponse())
@@ -1254,7 +1252,7 @@
GDBRemoteCommunicationClient::GetDefaultThreadId (lldb::tid_t &tid)
{
StringExtractorGDBRemote response;
- if (SendPacketAndWaitForResponse("qC",response,false) != PacketResult::Success)
+ if (SendPacketAndWaitForResponse("qC", response) != PacketResult::Success)
return false;
if (!response.IsNormalResponse())
@@ -1275,7 +1273,7 @@
{
m_qHostInfo_is_valid = eLazyBoolNo;
StringExtractorGDBRemote response;
- if (SendPacketAndWaitForResponse ("qHostInfo", response, false) == PacketResult::Success)
+ if (SendPacketAndWaitForResponse("qHostInfo", response) == PacketResult::Success)
{
if (response.IsNormalResponse())
{
@@ -1928,7 +1926,7 @@
GDBRemoteCommunicationClient::GetWorkingDir(FileSpec &working_dir)
{
StringExtractorGDBRemote response;
- if (SendPacketAndWaitForResponse ("qGetWorkingDir", response, false) == PacketResult::Success)
+ if (SendPacketAndWaitForResponse("qGetWorkingDir", response) == PacketResult::Success)
{
if (response.IsUnsupportedResponse())
return false;
@@ -2134,7 +2132,7 @@
GetHostInfo ();
StringExtractorGDBRemote response;
- if (SendPacketAndWaitForResponse ("qProcessInfo", response, false) == PacketResult::Success)
+ if (SendPacketAndWaitForResponse("qProcessInfo", response) == PacketResult::Success)
{
if (response.IsNormalResponse())
{
@@ -2703,7 +2701,7 @@
connection_urls.clear();
StringExtractorGDBRemote response;
- if (SendPacketAndWaitForResponse("qQueryGDBServer", response, false) != PacketResult::Success)
+ if (SendPacketAndWaitForResponse("qQueryGDBServer", response) != PacketResult::Success)
return 0;
StructuredData::ObjectSP data = StructuredData::ParseJSON(response.GetStringRef());
@@ -2919,7 +2917,7 @@
{
thread_ids.clear();
- Lock lock(*this, false);
+ Lock lock(*this);
if (lock)
{
sequence_mutex_unavailable = false;
@@ -2976,11 +2974,11 @@
lldb::addr_t
GDBRemoteCommunicationClient::GetShlibInfoAddr()
{
- Lock lock(*this, false);
+ Lock lock(*this);
if (lock)
{
StringExtractorGDBRemote response;
- if (SendPacketAndWaitForResponse("qShlibInfoAddr", ::strlen ("qShlibInfoAddr"), response, false) == PacketResult::Success)
+ if (SendPacketAndWaitForResponseNoLock("qShlibInfoAddr", response) == PacketResult::Success)
{
if (response.IsNormalResponse())
return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
@@ -3473,7 +3471,7 @@
bool
GDBRemoteCommunicationClient::ReadRegister(lldb::tid_t tid, uint32_t reg, StringExtractorGDBRemote &response)
{
- Lock lock(*this, false);
+ Lock lock(*this);
if (lock)
{
const bool thread_suffix_supported = GetThreadSuffixSupported();
@@ -3487,7 +3485,7 @@
else
packet_len = ::snprintf (packet, sizeof(packet), "p%x", reg);
assert (packet_len < ((int)sizeof(packet) - 1));
- return SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success;
+ return SendPacketAndWaitForResponse(packet, response) == PacketResult::Success;
}
}
else if (Log *log = ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_PROCESS | GDBR_LOG_PACKETS))
@@ -3502,7 +3500,7 @@
bool
GDBRemoteCommunicationClient::ReadAllRegisters (lldb::tid_t tid, StringExtractorGDBRemote &response)
{
- Lock lock(*this, false);
+ Lock lock(*this);
if (lock)
{
const bool thread_suffix_supported = GetThreadSuffixSupported();
@@ -3517,7 +3515,7 @@
else
packet_len = ::snprintf (packet, sizeof(packet), "g");
assert (packet_len < ((int)sizeof(packet) - 1));
- return SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success;
+ return SendPacketAndWaitForResponseNoLock(packet, response) == PacketResult::Success;
}
}
else if (Log *log = ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_PROCESS | GDBR_LOG_PACKETS))
@@ -3534,7 +3532,7 @@
return false;
m_supports_QSaveRegisterState = eLazyBoolYes;
- Lock lock(*this, false);
+ Lock lock(*this);
if (lock)
{
const bool thread_suffix_supported = GetThreadSuffixSupported();
@@ -3548,7 +3546,7 @@
StringExtractorGDBRemote response;
- if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success)
+ if (SendPacketAndWaitForResponseNoLock(packet, response) == PacketResult::Success)
{
if (response.IsUnsupportedResponse())
{
@@ -3582,7 +3580,7 @@
if (m_supports_QSaveRegisterState == eLazyBoolNo)
return false;
- Lock lock(*this, false);
+ Lock lock(*this);
if (lock)
{
const bool thread_suffix_supported = GetThreadSuffixSupported();
@@ -3595,8 +3593,8 @@
::snprintf (packet, sizeof(packet), "QRestoreRegisterState:%u" PRIx64 ";", save_id);
StringExtractorGDBRemote response;
-
- if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success)
+
+ if (SendPacketAndWaitForResponseNoLock(packet, response) == PacketResult::Success)
{
if (response.IsOKResponse())
{
@@ -3731,10 +3729,7 @@
<< std::hex << offset << ","
<< std::hex << size;
- GDBRemoteCommunication::PacketResult res =
- SendPacketAndWaitForResponse( packet.str().c_str(),
- chunk,
- false );
+ GDBRemoteCommunication::PacketResult res = SendPacketAndWaitForResponse(packet.str(), chunk);
if ( res != GDBRemoteCommunication::PacketResult::Success ) {
err.SetErrorString( "Error sending $qXfer packet" );
@@ -3818,7 +3813,7 @@
if (m_supports_qSymbol && m_qSymbol_requests_done == false)
{
- Lock lock(*this, false);
+ Lock lock(*this);
if (lock)
{
StreamString packet;
Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
===================================================================
--- source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
+++ source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
@@ -209,27 +209,19 @@
~History ();
- // For single char packets for ack, nack and /x03
void
- AddPacket (char packet_char,
- PacketType type,
- uint32_t bytes_transmitted);
+ AddPacket(llvm::StringRef packet, PacketType type, uint32_t bytes_transmitted);
void
- AddPacket (const std::string &src,
- uint32_t src_len,
- PacketType type,
- uint32_t bytes_transmitted);
-
- void
Dump (Stream &strm) const;
void
Dump (Log *log) const;
bool
DidDumpToLog () const
{
+ std::lock_guard<std::mutex> lock(m_mutex);
return m_dumped_to_log;
}
@@ -267,6 +259,7 @@
return i % m_packets.size();
}
+ mutable std::mutex m_mutex;
std::vector<Entry> m_packets;
uint32_t m_curr_idx;
uint32_t m_total_packet_count;
Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
===================================================================
--- source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
+++ source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
@@ -70,33 +70,14 @@
}
void
-GDBRemoteCommunication::History::AddPacket (char packet_char,
- PacketType type,
- uint32_t bytes_transmitted)
+GDBRemoteCommunication::History::AddPacket(llvm::StringRef packet, PacketType type, uint32_t bytes_transmitted)
{
+ std::lock_guard<std::mutex> lock(m_mutex);
const size_t size = m_packets.size();
if (size > 0)
{
const uint32_t idx = GetNextIndex();
- m_packets[idx].packet.assign (1, packet_char);
- m_packets[idx].type = type;
- m_packets[idx].bytes_transmitted = bytes_transmitted;
- m_packets[idx].packet_idx = m_total_packet_count;
- m_packets[idx].tid = Host::GetCurrentThreadID();
- }
-}
-
-void
-GDBRemoteCommunication::History::AddPacket (const std::string &src,
- uint32_t src_len,
- PacketType type,
- uint32_t bytes_transmitted)
-{
- const size_t size = m_packets.size();
- if (size > 0)
- {
- const uint32_t idx = GetNextIndex();
- m_packets[idx].packet.assign (src, 0, src_len);
+ m_packets[idx].packet = packet;
m_packets[idx].type = type;
m_packets[idx].bytes_transmitted = bytes_transmitted;
m_packets[idx].packet_idx = m_total_packet_count;
@@ -107,6 +88,7 @@
void
GDBRemoteCommunication::History::Dump (Stream &strm) const
{
+ std::lock_guard<std::mutex> lock(m_mutex);
const uint32_t size = GetNumPacketsInHistory ();
const uint32_t first_idx = GetFirstSavedPacketIndex ();
const uint32_t stop_idx = m_curr_idx + size;
@@ -128,6 +110,7 @@
void
GDBRemoteCommunication::History::Dump (Log *log) const
{
+ std::lock_guard<std::mutex> lock(m_mutex);
if (log && !m_dumped_to_log)
{
m_dumped_to_log = true;
@@ -206,7 +189,7 @@
const size_t bytes_written = Write (&ch, 1, status, NULL);
if (log)
log->Printf ("<%4" PRIu64 "> send packet: %c", (uint64_t)bytes_written, ch);
- m_history.AddPacket (ch, History::ePacketTypeSend, bytes_written);
+ m_history.AddPacket(llvm::StringRef(&ch, 1), History::ePacketTypeSend, bytes_written);
return bytes_written;
}
@@ -219,7 +202,7 @@
const size_t bytes_written = Write (&ch, 1, status, NULL);
if (log)
log->Printf("<%4" PRIu64 "> send packet: %c", (uint64_t)bytes_written, ch);
- m_history.AddPacket (ch, History::ePacketTypeSend, bytes_written);
+ m_history.AddPacket(llvm::StringRef(&ch, 1), History::ePacketTypeSend, bytes_written);
return bytes_written;
}
@@ -278,8 +261,7 @@
log->Printf("<%4" PRIu64 "> send packet: %.*s", (uint64_t)bytes_written, (int)packet_length, packet_data);
}
- m_history.AddPacket (packet.GetString(), packet_length, History::ePacketTypeSend, bytes_written);
-
+ m_history.AddPacket(packet.GetString(), History::ePacketTypeSend, bytes_written);
if (bytes_written == packet_length)
{
@@ -955,7 +937,7 @@
}
}
- m_history.AddPacket (m_bytes.c_str(), total_length, History::ePacketTypeRecv, total_length);
+ m_history.AddPacket(m_bytes, History::ePacketTypeRecv, total_length);
// Clear packet_str in case there is some existing data in it.
packet_str.clear();
Index: source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h
===================================================================
--- source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h
+++ source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h
@@ -14,6 +14,8 @@
#include <condition_variable>
+#include "llvm/Support/RWMutex.h"
+
namespace lldb_private
{
namespace process_gdb_remote
@@ -33,34 +35,16 @@
HandleStopReply() = 0;
};
- GDBRemoteClientBase(const char *comm_name, const char *listener_name);
-
- bool
- SendAsyncSignal(int signo);
-
- bool
- Interrupt();
-
- lldb::StateType
- SendContinuePacketAndWaitForResponse(ContinueDelegate &delegate, const UnixSignals &signals,
- llvm::StringRef payload, StringExtractorGDBRemote &response);
-
- PacketResult
- SendPacketAndWaitForResponse(const char *payload, size_t len, StringExtractorGDBRemote &response, bool send_async)
- {
- return SendPacketAndWaitForResponse(llvm::StringRef(payload, len), response, send_async);
- }
-
- PacketResult
- SendPacketAndWaitForResponse(llvm::StringRef payload, StringExtractorGDBRemote &response, bool send_async);
-
- bool
- SendvContPacket(llvm::StringRef payload, StringExtractorGDBRemote &response);
-
class Lock
{
public:
- Lock(GDBRemoteClientBase &comm, bool interrupt);
+ enum Kind
+ {
+ Shared,
+ Exclusive
+ };
+
+ Lock(GDBRemoteClientBase &comm, Kind kind = Exclusive, bool interrupt = false);
~Lock();
explicit operator bool() { return m_acquired; }
@@ -73,15 +57,40 @@
}
private:
- std::unique_lock<std::recursive_mutex> m_async_lock;
GDBRemoteClientBase &m_comm;
+ Kind m_kind;
bool m_acquired;
bool m_did_interrupt;
void
SyncWithContinueThread(bool interrupt);
};
+ GDBRemoteClientBase(const char *comm_name, const char *listener_name);
+
+ bool
+ SendAsyncSignal(int signo);
+
+ bool
+ Interrupt();
+
+ lldb::StateType
+ SendContinuePacketAndWaitForResponse(ContinueDelegate &delegate, const UnixSignals &signals,
+ llvm::StringRef payload, StringExtractorGDBRemote &response);
+
+ PacketResult
+ SendPacketAndWaitForResponse(const char *payload, size_t len, StringExtractorGDBRemote &response, bool send_async)
+ {
+ return SendPacketAndWaitForResponse(llvm::StringRef(payload, len), response, Lock::Exclusive, send_async);
+ }
+
+ PacketResult
+ SendPacketAndWaitForResponse(llvm::StringRef payload, StringExtractorGDBRemote &response,
+ Lock::Kind kind = Lock::Exclusive, bool send_async = false);
+
+ bool
+ SendvContPacket(llvm::StringRef payload, StringExtractorGDBRemote &response);
+
protected:
PacketResult
SendPacketAndWaitForResponseNoLock(llvm::StringRef payload, StringExtractorGDBRemote &response);
@@ -114,13 +123,21 @@
bool m_should_stop; // Whether we should resume after a stop.
// end of continue thread synchronization block
- // This handles the synchronization between individual async threads. For now they just use a
- // simple mutex.
- std::recursive_mutex m_async_mutex;
+ // This handles the synchronization between individual async threads. Either many threads can
+ // share the connection, or one thread has exclusive access.
+ llvm::sys::RWMutex m_async_mutex;
+
+ // The data structures for matching up concurrent requests and responses.
+ std::mutex m_queue_mutex;
+ std::condition_variable m_queue_cv;
+ std::queue<const void *> m_queue;
bool
ShouldStop(const UnixSignals &signals, StringExtractorGDBRemote &response);
+ PacketResult
+ ReadAndValidatePacket(StringExtractorGDBRemote &response);
+
class ContinueLock
{
public:
Index: source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp
===================================================================
--- source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp
+++ source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp
@@ -140,7 +140,7 @@
bool
GDBRemoteClientBase::SendAsyncSignal(int signo)
{
- Lock lock(*this, true);
+ Lock lock(*this, Lock::Exclusive, true);
if (!lock || !lock.DidInterrupt())
return false;
@@ -153,17 +153,17 @@
bool
GDBRemoteClientBase::Interrupt()
{
- Lock lock(*this, true);
+ Lock lock(*this, Lock::Exclusive, true);
if (!lock.DidInterrupt())
return false;
m_should_stop = true;
return true;
}
GDBRemoteCommunication::PacketResult
GDBRemoteClientBase::SendPacketAndWaitForResponse(llvm::StringRef payload, StringExtractorGDBRemote &response,
- bool send_async)
+ Lock::Kind kind, bool send_async)
{
- Lock lock(*this, send_async);
+ Lock lock(*this, kind, send_async);
if (!lock)
{
if (Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS))
@@ -178,25 +178,49 @@
GDBRemoteCommunication::PacketResult
GDBRemoteClientBase::SendPacketAndWaitForResponseNoLock(llvm::StringRef payload, StringExtractorGDBRemote &response)
{
- PacketResult packet_result = SendPacketNoLock(payload.data(), payload.size());
- if (packet_result != PacketResult::Success)
- return packet_result;
+ PacketResult packet_result;
+ {
+ std::unique_lock<std::mutex> lock(m_queue_mutex);
+
+ packet_result = SendPacketNoLock(payload.data(), payload.size());
+ if (packet_result != PacketResult::Success)
+ return packet_result;
+
+ // Any unique value would work here. Address of a local variable is guaranteed to satisfy that.
+ m_queue.push(&packet_result);
+ m_cv.wait(lock, [this, &packet_result] { return m_queue.front() == &packet_result; });
+ }
+
+ // Do the blocking part (reading) with the queue lock released.
+ packet_result = ReadAndValidatePacket(response);
+
+ {
+ std::lock_guard<std::mutex> lock(m_queue_mutex);
+ lldbassert(m_queue.front() == &packet_result);
+ m_queue.pop();
+ }
+ m_queue_cv.notify_all();
+ return packet_result;
+}
+GDBRemoteCommunication::PacketResult
+GDBRemoteClientBase::ReadAndValidatePacket(StringExtractorGDBRemote &response)
+{
+ PacketResult packet_result;
const size_t max_response_retries = 3;
for (size_t i = 0; i < max_response_retries; ++i)
{
packet_result = ReadPacket(response, GetPacketTimeoutInMicroSeconds(), true);
// Make sure we received a response
if (packet_result != PacketResult::Success)
- return packet_result;
+ break;
// Make sure our response is valid for the payload that was sent
if (response.ValidateResponse())
- return packet_result;
+ break;
// Response says it wasn't valid
Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS);
if (log)
- log->Printf("error: packet with payload \"%.*s\" got invalid response \"%s\": %s", int(payload.size()),
- payload.data(), response.GetStringRef().c_str(),
+ log->Printf("error: got invalid response \"%s\": %s", response.GetStringRef().c_str(),
(i == (max_response_retries - 1)) ? "using invalid response and giving up"
: "ignoring response and waiting for another");
}
@@ -211,7 +235,7 @@
log->Printf("GDBRemoteCommunicationClient::%s ()", __FUNCTION__);
// we want to lock down packet sending while we continue
- Lock lock(*this, true);
+ Lock lock(*this, Lock::Exclusive, true);
if (log)
log->Printf("GDBRemoteCommunicationClient::%s () sending vCont packet: %.*s", __FUNCTION__, int(payload.size()),
@@ -330,12 +354,17 @@
// GDBRemoteClientBase::Lock //
///////////////////////////////
-GDBRemoteClientBase::Lock::Lock(GDBRemoteClientBase &comm, bool interrupt)
- : m_async_lock(comm.m_async_mutex, std::defer_lock), m_comm(comm), m_acquired(false), m_did_interrupt(false)
+GDBRemoteClientBase::Lock::Lock(GDBRemoteClientBase &comm, Kind kind, bool interrupt)
+ : m_comm(comm), m_kind(kind), m_acquired(false), m_did_interrupt(false)
{
SyncWithContinueThread(interrupt);
- if (m_acquired)
- m_async_lock.lock();
+ if (!m_acquired)
+ return;
+
+ if (m_kind == Shared)
+ m_comm.m_async_mutex.lock_shared();
+ else
+ m_comm.m_async_mutex.lock();
}
void
@@ -376,6 +405,12 @@
{
if (!m_acquired)
return;
+
+ if (m_kind == Shared)
+ m_comm.m_async_mutex.unlock_shared();
+ else
+ m_comm.m_async_mutex.unlock();
+
{
std::unique_lock<std::mutex> lock(m_comm.m_mutex);
--m_comm.m_async_count;
_______________________________________________
lldb-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits