diff options
Diffstat (limited to 'lldb/source/Core/Communication.cpp')
-rw-r--r-- | lldb/source/Core/Communication.cpp | 38 |
1 files changed, 25 insertions, 13 deletions
diff --git a/lldb/source/Core/Communication.cpp b/lldb/source/Core/Communication.cpp index 0afd897a2093..b358e70b1a91 100644 --- a/lldb/source/Core/Communication.cpp +++ b/lldb/source/Core/Communication.cpp @@ -1,4 +1,4 @@ -//===-- Communication.cpp ---------------------------------------*- C++ -*-===// +//===-- Communication.cpp -------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -71,8 +71,8 @@ Communication::~Communication() { void Communication::Clear() { SetReadThreadBytesReceivedCallback(nullptr, nullptr); - Disconnect(nullptr); StopReadThread(nullptr); + Disconnect(nullptr); } ConnectionStatus Communication::Connect(const char *url, Status *error_ptr) { @@ -93,6 +93,8 @@ ConnectionStatus Communication::Disconnect(Status *error_ptr) { LLDB_LOG(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_COMMUNICATION), "{0} Communication::Disconnect ()", this); + assert((!m_read_thread_enabled || m_read_thread_did_exit) && + "Disconnecting while the read thread is running is racy!"); lldb::ConnectionSP connection_sp(m_connection_sp); if (connection_sp) { ConnectionStatus status = connection_sp->Disconnect(error_ptr); @@ -315,16 +317,12 @@ lldb::thread_result_t Communication::ReadThread(lldb::thread_arg_t p) { Status error; ConnectionStatus status = eConnectionStatusSuccess; bool done = false; + bool disconnect = false; while (!done && comm->m_read_thread_enabled) { size_t bytes_read = comm->ReadFromConnection( buf, sizeof(buf), std::chrono::seconds(5), status, &error); - if (bytes_read > 0) + if (bytes_read > 0 || status == eConnectionStatusEndOfFile) comm->AppendBytesToCache(buf, bytes_read, true, status); - else if ((bytes_read == 0) && status == eConnectionStatusEndOfFile) { - if (comm->GetCloseOnEOF()) - comm->Disconnect(); - comm->AppendBytesToCache(buf, bytes_read, true, status); - } switch (status) { case eConnectionStatusSuccess: @@ -332,11 +330,12 @@ lldb::thread_result_t Communication::ReadThread(lldb::thread_arg_t p) { case eConnectionStatusEndOfFile: done = true; + disconnect = comm->GetCloseOnEOF(); break; case eConnectionStatusError: // Check GetError() for details if (error.GetType() == eErrorTypePOSIX && error.GetError() == EIO) { // EIO on a pipe is usually caused by remote shutdown - comm->Disconnect(); + disconnect = comm->GetCloseOnEOF(); done = true; } if (error.Fail()) @@ -365,9 +364,22 @@ lldb::thread_result_t Communication::ReadThread(lldb::thread_arg_t p) { if (log) LLDB_LOGF(log, "%p Communication::ReadThread () thread exiting...", p); - comm->m_read_thread_did_exit = true; + // Handle threads wishing to synchronize with us. + { + // Prevent new ones from showing up. + comm->m_read_thread_did_exit = true; + + // Unblock any existing thread waiting for the synchronization signal. + comm->BroadcastEvent(eBroadcastBitNoMorePendingInput); + + // Wait for the thread to finish... + std::lock_guard<std::mutex> guard(comm->m_synchronize_mutex); + // ... and disconnect. + if (disconnect) + comm->Disconnect(); + } + // Let clients know that this thread is exiting - comm->BroadcastEvent(eBroadcastBitNoMorePendingInput); comm->BroadcastEvent(eBroadcastBitReadThreadDidExit); return {}; } @@ -399,10 +411,10 @@ void Communication::SynchronizeWithReadThread() { listener_sp->GetEvent(event_sp, llvm::None); } -void Communication::SetConnection(Connection *connection) { +void Communication::SetConnection(std::unique_ptr<Connection> connection) { Disconnect(nullptr); StopReadThread(nullptr); - m_connection_sp.reset(connection); + m_connection_sp = std::move(connection); } const char * |