180814287SRaphael Isemann //===-- Communication.cpp -------------------------------------------------===//
230fdc8d8SChris Lattner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
630fdc8d8SChris Lattner //
730fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
830fdc8d8SChris Lattner 
930fdc8d8SChris Lattner #include "lldb/Core/Communication.h"
102f3df613SZachary Turner 
1139de3110SZachary Turner #include "lldb/Host/HostThread.h"
1239de3110SZachary Turner #include "lldb/Host/ThreadLauncher.h"
134ccd9954SPavel Labath #include "lldb/Utility/Connection.h"
14672d2c12SJonas Devlieghere #include "lldb/Utility/ConstString.h"
15181b823bSPavel Labath #include "lldb/Utility/Event.h"
16c34698a8SPavel Labath #include "lldb/Utility/LLDBLog.h"
17181b823bSPavel Labath #include "lldb/Utility/Listener.h"
186f9e6901SZachary Turner #include "lldb/Utility/Log.h"
19672d2c12SJonas Devlieghere #include "lldb/Utility/Status.h"
202f3df613SZachary Turner 
21672d2c12SJonas Devlieghere #include "llvm/ADT/None.h"
22672d2c12SJonas Devlieghere #include "llvm/ADT/Optional.h"
23672d2c12SJonas Devlieghere #include "llvm/Support/Compiler.h"
242f3df613SZachary Turner 
25672d2c12SJonas Devlieghere #include <algorithm>
26672d2c12SJonas Devlieghere #include <chrono>
272f3df613SZachary Turner #include <cstring>
28672d2c12SJonas Devlieghere #include <memory>
292f3df613SZachary Turner 
3076e47d48SRaphael Isemann #include <cerrno>
3176e47d48SRaphael Isemann #include <cinttypes>
3276e47d48SRaphael Isemann #include <cstdio>
3330fdc8d8SChris Lattner 
3430fdc8d8SChris Lattner using namespace lldb;
3530fdc8d8SChris Lattner using namespace lldb_private;
3630fdc8d8SChris Lattner 
GetStaticBroadcasterClass()37b9c1b51eSKate Stone ConstString &Communication::GetStaticBroadcasterClass() {
384bddaeb5SJim Ingham   static ConstString class_name("lldb.communication");
394bddaeb5SJim Ingham   return class_name;
404bddaeb5SJim Ingham }
414bddaeb5SJim Ingham 
Communication(const char * name)4216ff8604SSaleem Abdulrasool Communication::Communication(const char *name)
43b9c1b51eSKate Stone     : Broadcaster(nullptr, name), m_connection_sp(),
44b9c1b51eSKate Stone       m_read_thread_enabled(false), m_read_thread_did_exit(false), m_bytes(),
45b9c1b51eSKate Stone       m_bytes_mutex(), m_write_mutex(), m_synchronize_mutex(),
46b9c1b51eSKate Stone       m_callback(nullptr), m_callback_baton(nullptr), m_close_on_eof(true)
4730fdc8d8SChris Lattner 
4830fdc8d8SChris Lattner {
49b2a9cf77SJonas Devlieghere 
50a007a6d8SPavel Labath   LLDB_LOG(GetLog(LLDBLog::Object | LLDBLog::Communication),
51eaedc5efSJonas Devlieghere            "{0} Communication::Communication (name = {1})", this, name);
5295bf0fd3SGreg Clayton 
5395bf0fd3SGreg Clayton   SetEventName(eBroadcastBitDisconnected, "disconnected");
5495bf0fd3SGreg Clayton   SetEventName(eBroadcastBitReadThreadGotBytes, "got bytes");
5595bf0fd3SGreg Clayton   SetEventName(eBroadcastBitReadThreadDidExit, "read thread did exit");
5695bf0fd3SGreg Clayton   SetEventName(eBroadcastBitReadThreadShouldExit, "read thread should exit");
5795bf0fd3SGreg Clayton   SetEventName(eBroadcastBitPacketAvailable, "packet available");
583f5df53fSPavel Labath   SetEventName(eBroadcastBitNoMorePendingInput, "no more pending input");
594bddaeb5SJim Ingham 
604bddaeb5SJim Ingham   CheckInWithManager();
6130fdc8d8SChris Lattner }
6230fdc8d8SChris Lattner 
~Communication()63b9c1b51eSKate Stone Communication::~Communication() {
64a007a6d8SPavel Labath   LLDB_LOG(GetLog(LLDBLog::Object | LLDBLog::Communication),
65eaedc5efSJonas Devlieghere            "{0} Communication::~Communication (name = {1})", this,
66b9c1b51eSKate Stone            GetBroadcasterName().AsCString());
6730fdc8d8SChris Lattner   Clear();
6830fdc8d8SChris Lattner }
6930fdc8d8SChris Lattner 
Clear()70b9c1b51eSKate Stone void Communication::Clear() {
71896ddd03SEugene Zelenko   SetReadThreadBytesReceivedCallback(nullptr, nullptr);
72896ddd03SEugene Zelenko   StopReadThread(nullptr);
739321255bSPavel Labath   Disconnect(nullptr);
7430fdc8d8SChris Lattner }
7530fdc8d8SChris Lattner 
Connect(const char * url,Status * error_ptr)7697206d57SZachary Turner ConnectionStatus Communication::Connect(const char *url, Status *error_ptr) {
7730fdc8d8SChris Lattner   Clear();
7830fdc8d8SChris Lattner 
79a007a6d8SPavel Labath   LLDB_LOG(GetLog(LLDBLog::Communication),
80eaedc5efSJonas Devlieghere            "{0} Communication::Connect (url = {1})", this, url);
8130fdc8d8SChris Lattner 
828b2fe6dcSGreg Clayton   lldb::ConnectionSP connection_sp(m_connection_sp);
83896ddd03SEugene Zelenko   if (connection_sp)
848b2fe6dcSGreg Clayton     return connection_sp->Connect(url, error_ptr);
8530fdc8d8SChris Lattner   if (error_ptr)
8630fdc8d8SChris Lattner     error_ptr->SetErrorString("Invalid connection.");
8730fdc8d8SChris Lattner   return eConnectionStatusNoConnection;
8830fdc8d8SChris Lattner }
8930fdc8d8SChris Lattner 
Disconnect(Status * error_ptr)9097206d57SZachary Turner ConnectionStatus Communication::Disconnect(Status *error_ptr) {
91a007a6d8SPavel Labath   LLDB_LOG(GetLog(LLDBLog::Communication), "{0} Communication::Disconnect ()",
92a007a6d8SPavel Labath            this);
9330fdc8d8SChris Lattner 
949321255bSPavel Labath   assert((!m_read_thread_enabled || m_read_thread_did_exit) &&
959321255bSPavel Labath          "Disconnecting while the read thread is running is racy!");
968b2fe6dcSGreg Clayton   lldb::ConnectionSP connection_sp(m_connection_sp);
97b9c1b51eSKate Stone   if (connection_sp) {
988b2fe6dcSGreg Clayton     ConnectionStatus status = connection_sp->Disconnect(error_ptr);
9905097246SAdrian Prantl     // We currently don't protect connection_sp with any mutex for multi-
10005097246SAdrian Prantl     // threaded environments. So lets not nuke our connection class without
10105097246SAdrian Prantl     // putting some multi-threaded protections in. We also probably don't want
10205097246SAdrian Prantl     // to pay for the overhead it might cause if every time we access the
10305097246SAdrian Prantl     // connection we have to take a lock.
104bfae66aeSGreg Clayton     //
10505097246SAdrian Prantl     // This unique pointer will cleanup after itself when this object goes
10605097246SAdrian Prantl     // away, so there is no need to currently have it destroy itself
1074ebdee0aSBruce Mitchener     // immediately upon disconnect.
1088b2fe6dcSGreg Clayton     // connection_sp.reset();
10930fdc8d8SChris Lattner     return status;
11030fdc8d8SChris Lattner   }
11130fdc8d8SChris Lattner   return eConnectionStatusNoConnection;
11230fdc8d8SChris Lattner }
11330fdc8d8SChris Lattner 
IsConnected() const114b9c1b51eSKate Stone bool Communication::IsConnected() const {
1158b2fe6dcSGreg Clayton   lldb::ConnectionSP connection_sp(m_connection_sp);
116896ddd03SEugene Zelenko   return (connection_sp ? connection_sp->IsConnected() : false);
11730fdc8d8SChris Lattner }
11830fdc8d8SChris Lattner 
HasConnection() const119b9c1b51eSKate Stone bool Communication::HasConnection() const {
120896ddd03SEugene Zelenko   return m_connection_sp.get() != nullptr;
12130fdc8d8SChris Lattner }
12230fdc8d8SChris Lattner 
Read(void * dst,size_t dst_len,const Timeout<std::micro> & timeout,ConnectionStatus & status,Status * error_ptr)123c4063eeeSPavel Labath size_t Communication::Read(void *dst, size_t dst_len,
124c4063eeeSPavel Labath                            const Timeout<std::micro> &timeout,
12597206d57SZachary Turner                            ConnectionStatus &status, Status *error_ptr) {
126a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Communication);
127d02b1c83SPavel Labath   LLDB_LOG(
128d02b1c83SPavel Labath       log,
129d02b1c83SPavel Labath       "this = {0}, dst = {1}, dst_len = {2}, timeout = {3}, connection = {4}",
130d02b1c83SPavel Labath       this, dst, dst_len, timeout, m_connection_sp.get());
13130fdc8d8SChris Lattner 
132b9c1b51eSKate Stone   if (m_read_thread_enabled) {
13330fdc8d8SChris Lattner     // We have a dedicated read thread that is getting data for us
13430fdc8d8SChris Lattner     size_t cached_bytes = GetCachedBytes(dst, dst_len);
135c4063eeeSPavel Labath     if (cached_bytes > 0 || (timeout && timeout->count() == 0)) {
13630fdc8d8SChris Lattner       status = eConnectionStatusSuccess;
13730fdc8d8SChris Lattner       return cached_bytes;
13830fdc8d8SChris Lattner     }
13930fdc8d8SChris Lattner 
140b9c1b51eSKate Stone     if (!m_connection_sp) {
14130fdc8d8SChris Lattner       if (error_ptr)
14230fdc8d8SChris Lattner         error_ptr->SetErrorString("Invalid connection.");
14330fdc8d8SChris Lattner       status = eConnectionStatusNoConnection;
14430fdc8d8SChris Lattner       return 0;
14530fdc8d8SChris Lattner     }
14630fdc8d8SChris Lattner 
147583bbb1dSJim Ingham     ListenerSP listener_sp(Listener::MakeListener("Communication::Read"));
148b9c1b51eSKate Stone     listener_sp->StartListeningForEvents(
149b9c1b51eSKate Stone         this, eBroadcastBitReadThreadGotBytes | eBroadcastBitReadThreadDidExit);
15030fdc8d8SChris Lattner     EventSP event_sp;
151d35031e1SPavel Labath     while (listener_sp->GetEvent(event_sp, timeout)) {
15230fdc8d8SChris Lattner       const uint32_t event_type = event_sp->GetType();
153b9c1b51eSKate Stone       if (event_type & eBroadcastBitReadThreadGotBytes) {
15430fdc8d8SChris Lattner         return GetCachedBytes(dst, dst_len);
15530fdc8d8SChris Lattner       }
15630fdc8d8SChris Lattner 
157b9c1b51eSKate Stone       if (event_type & eBroadcastBitReadThreadDidExit) {
15835856696STamas Berghammer         if (GetCloseOnEOF())
159896ddd03SEugene Zelenko           Disconnect(nullptr);
16030fdc8d8SChris Lattner         break;
16130fdc8d8SChris Lattner       }
16230fdc8d8SChris Lattner     }
16330fdc8d8SChris Lattner     return 0;
16430fdc8d8SChris Lattner   }
16530fdc8d8SChris Lattner 
16630fdc8d8SChris Lattner   // We aren't using a read thread, just read the data synchronously in this
16730fdc8d8SChris Lattner   // thread.
168c4063eeeSPavel Labath   return ReadFromConnection(dst, dst_len, timeout, status, error_ptr);
16930fdc8d8SChris Lattner }
17030fdc8d8SChris Lattner 
Write(const void * src,size_t src_len,ConnectionStatus & status,Status * error_ptr)171b9c1b51eSKate Stone size_t Communication::Write(const void *src, size_t src_len,
17297206d57SZachary Turner                             ConnectionStatus &status, Status *error_ptr) {
1738b2fe6dcSGreg Clayton   lldb::ConnectionSP connection_sp(m_connection_sp);
1748b2fe6dcSGreg Clayton 
17516ff8604SSaleem Abdulrasool   std::lock_guard<std::mutex> guard(m_write_mutex);
176a007a6d8SPavel Labath   LLDB_LOG(GetLog(LLDBLog::Communication),
1774f1c90a6SRyan Mansfield            "{0} Communication::Write (src = {1}, src_len = {2}"
1784f1c90a6SRyan Mansfield            ") connection = {3}",
179b9c1b51eSKate Stone            this, src, (uint64_t)src_len, connection_sp.get());
18030fdc8d8SChris Lattner 
181896ddd03SEugene Zelenko   if (connection_sp)
1828b2fe6dcSGreg Clayton     return connection_sp->Write(src, src_len, status, error_ptr);
18330fdc8d8SChris Lattner 
18430fdc8d8SChris Lattner   if (error_ptr)
18530fdc8d8SChris Lattner     error_ptr->SetErrorString("Invalid connection.");
18630fdc8d8SChris Lattner   status = eConnectionStatusNoConnection;
18730fdc8d8SChris Lattner   return 0;
18830fdc8d8SChris Lattner }
18930fdc8d8SChris Lattner 
WriteAll(const void * src,size_t src_len,ConnectionStatus & status,Status * error_ptr)190f279e50fSMichał Górny size_t Communication::WriteAll(const void *src, size_t src_len,
191f279e50fSMichał Górny                                ConnectionStatus &status, Status *error_ptr) {
192f279e50fSMichał Górny   size_t total_written = 0;
193f279e50fSMichał Górny   do
194f279e50fSMichał Górny     total_written += Write(static_cast<const char *>(src) + total_written,
195f279e50fSMichał Górny                            src_len - total_written, status, error_ptr);
196f279e50fSMichał Górny   while (status == eConnectionStatusSuccess && total_written < src_len);
197f279e50fSMichał Górny   return total_written;
198f279e50fSMichał Górny }
199f279e50fSMichał Górny 
StartReadThread(Status * error_ptr)20097206d57SZachary Turner bool Communication::StartReadThread(Status *error_ptr) {
2011cb6496eSGreg Clayton   if (error_ptr)
2021cb6496eSGreg Clayton     error_ptr->Clear();
2031cb6496eSGreg Clayton 
204acee96aeSZachary Turner   if (m_read_thread.IsJoinable())
20530fdc8d8SChris Lattner     return true;
20630fdc8d8SChris Lattner 
207a007a6d8SPavel Labath   LLDB_LOG(GetLog(LLDBLog::Communication),
208eaedc5efSJonas Devlieghere            "{0} Communication::StartReadThread ()", this);
20930fdc8d8SChris Lattner 
210db203e02SRaphael Isemann   const std::string thread_name =
211db203e02SRaphael Isemann       llvm::formatv("<lldb.comm.{0}>", GetBroadcasterName());
21230fdc8d8SChris Lattner 
21386c3f345SGreg Clayton   m_read_thread_enabled = true;
2143f5df53fSPavel Labath   m_read_thread_did_exit = false;
215f39c2e18SJonas Devlieghere   auto maybe_thread = ThreadLauncher::LaunchThread(
216*d0810779SPavel Labath       thread_name, [this] { return ReadThread(); });
217f39c2e18SJonas Devlieghere   if (maybe_thread) {
218f39c2e18SJonas Devlieghere     m_read_thread = *maybe_thread;
219f39c2e18SJonas Devlieghere   } else {
220f39c2e18SJonas Devlieghere     if (error_ptr)
221f39c2e18SJonas Devlieghere       *error_ptr = Status(maybe_thread.takeError());
222f39c2e18SJonas Devlieghere     else {
223a007a6d8SPavel Labath       LLDB_LOG(GetLog(LLDBLog::Host), "failed to launch host thread: {}",
224f39c2e18SJonas Devlieghere                llvm::toString(maybe_thread.takeError()));
225f39c2e18SJonas Devlieghere     }
226f39c2e18SJonas Devlieghere   }
227f39c2e18SJonas Devlieghere 
228acee96aeSZachary Turner   if (!m_read_thread.IsJoinable())
22986c3f345SGreg Clayton     m_read_thread_enabled = false;
230f39c2e18SJonas Devlieghere 
23126661bcaSGreg Clayton   return m_read_thread_enabled;
23230fdc8d8SChris Lattner }
23330fdc8d8SChris Lattner 
StopReadThread(Status * error_ptr)23497206d57SZachary Turner bool Communication::StopReadThread(Status *error_ptr) {
235acee96aeSZachary Turner   if (!m_read_thread.IsJoinable())
23630fdc8d8SChris Lattner     return true;
23730fdc8d8SChris Lattner 
238a007a6d8SPavel Labath   LLDB_LOG(GetLog(LLDBLog::Communication),
239eaedc5efSJonas Devlieghere            "{0} Communication::StopReadThread ()", this);
24030fdc8d8SChris Lattner 
24130fdc8d8SChris Lattner   m_read_thread_enabled = false;
24230fdc8d8SChris Lattner 
243896ddd03SEugene Zelenko   BroadcastEvent(eBroadcastBitReadThreadShouldExit, nullptr);
24430fdc8d8SChris Lattner 
24539de3110SZachary Turner   // error = m_read_thread.Cancel();
24630fdc8d8SChris Lattner 
24797206d57SZachary Turner   Status error = m_read_thread.Join(nullptr);
24839de3110SZachary Turner   return error.Success();
24930fdc8d8SChris Lattner }
25030fdc8d8SChris Lattner 
JoinReadThread(Status * error_ptr)25197206d57SZachary Turner bool Communication::JoinReadThread(Status *error_ptr) {
252acee96aeSZachary Turner   if (!m_read_thread.IsJoinable())
25359042602SGreg Clayton     return true;
25459042602SGreg Clayton 
25597206d57SZachary Turner   Status error = m_read_thread.Join(nullptr);
25639de3110SZachary Turner   return error.Success();
25759042602SGreg Clayton }
25830fdc8d8SChris Lattner 
GetCachedBytes(void * dst,size_t dst_len)259b9c1b51eSKate Stone size_t Communication::GetCachedBytes(void *dst, size_t dst_len) {
26016ff8604SSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(m_bytes_mutex);
261b9c1b51eSKate Stone   if (!m_bytes.empty()) {
26205097246SAdrian Prantl     // If DST is nullptr and we have a thread, then return the number of bytes
26305097246SAdrian Prantl     // that are available so the caller can call again
264896ddd03SEugene Zelenko     if (dst == nullptr)
26530fdc8d8SChris Lattner       return m_bytes.size();
26630fdc8d8SChris Lattner 
26730fdc8d8SChris Lattner     const size_t len = std::min<size_t>(dst_len, m_bytes.size());
26830fdc8d8SChris Lattner 
269471b31ceSGreg Clayton     ::memcpy(dst, m_bytes.c_str(), len);
27030fdc8d8SChris Lattner     m_bytes.erase(m_bytes.begin(), m_bytes.begin() + len);
27130fdc8d8SChris Lattner 
27230fdc8d8SChris Lattner     return len;
27330fdc8d8SChris Lattner   }
27430fdc8d8SChris Lattner   return 0;
27530fdc8d8SChris Lattner }
27630fdc8d8SChris Lattner 
AppendBytesToCache(const uint8_t * bytes,size_t len,bool broadcast,ConnectionStatus status)277b9c1b51eSKate Stone void Communication::AppendBytesToCache(const uint8_t *bytes, size_t len,
278b9c1b51eSKate Stone                                        bool broadcast,
279b9c1b51eSKate Stone                                        ConnectionStatus status) {
280a007a6d8SPavel Labath   LLDB_LOG(GetLog(LLDBLog::Communication),
281eaedc5efSJonas Devlieghere            "{0} Communication::AppendBytesToCache (src = {1}, src_len = {2}, "
282eaedc5efSJonas Devlieghere            "broadcast = {3})",
28343e0af06SGreg Clayton            this, bytes, (uint64_t)len, broadcast);
284b9c1b51eSKate Stone   if ((bytes == nullptr || len == 0) &&
285b9c1b51eSKate Stone       (status != lldb::eConnectionStatusEndOfFile))
28630fdc8d8SChris Lattner     return;
287b9c1b51eSKate Stone   if (m_callback) {
28830fdc8d8SChris Lattner     // If the user registered a callback, then call it and do not broadcast
28930fdc8d8SChris Lattner     m_callback(m_callback_baton, bytes, len);
290b9c1b51eSKate Stone   } else if (bytes != nullptr && len > 0) {
29116ff8604SSaleem Abdulrasool     std::lock_guard<std::recursive_mutex> guard(m_bytes_mutex);
29230fdc8d8SChris Lattner     m_bytes.append((const char *)bytes, len);
29330fdc8d8SChris Lattner     if (broadcast)
29430fdc8d8SChris Lattner       BroadcastEventIfUnique(eBroadcastBitReadThreadGotBytes);
29530fdc8d8SChris Lattner   }
29630fdc8d8SChris Lattner }
29730fdc8d8SChris Lattner 
ReadFromConnection(void * dst,size_t dst_len,const Timeout<std::micro> & timeout,ConnectionStatus & status,Status * error_ptr)298b9c1b51eSKate Stone size_t Communication::ReadFromConnection(void *dst, size_t dst_len,
299c4063eeeSPavel Labath                                          const Timeout<std::micro> &timeout,
30073bf5dbdSGreg Clayton                                          ConnectionStatus &status,
30197206d57SZachary Turner                                          Status *error_ptr) {
3028b2fe6dcSGreg Clayton   lldb::ConnectionSP connection_sp(m_connection_sp);
3032f159a5fSPavel Labath   if (connection_sp)
3042f159a5fSPavel Labath     return connection_sp->Read(dst, dst_len, timeout, status, error_ptr);
305c4063eeeSPavel Labath 
306c4063eeeSPavel Labath   if (error_ptr)
307c4063eeeSPavel Labath     error_ptr->SetErrorString("Invalid connection.");
308c4063eeeSPavel Labath   status = eConnectionStatusNoConnection;
309c4063eeeSPavel Labath   return 0;
31030fdc8d8SChris Lattner }
31130fdc8d8SChris Lattner 
ReadThreadIsRunning()312b9c1b51eSKate Stone bool Communication::ReadThreadIsRunning() { return m_read_thread_enabled; }
31330fdc8d8SChris Lattner 
ReadThread()314*d0810779SPavel Labath lldb::thread_result_t Communication::ReadThread() {
315a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Communication);
31630fdc8d8SChris Lattner 
317*d0810779SPavel Labath   LLDB_LOG(log, "Communication({0}) thread starting...", this);
31830fdc8d8SChris Lattner 
31930fdc8d8SChris Lattner   uint8_t buf[1024];
32030fdc8d8SChris Lattner 
32197206d57SZachary Turner   Status error;
32230fdc8d8SChris Lattner   ConnectionStatus status = eConnectionStatusSuccess;
32330fdc8d8SChris Lattner   bool done = false;
324769d7041SPavel Labath   bool disconnect = false;
325*d0810779SPavel Labath   while (!done && m_read_thread_enabled) {
326*d0810779SPavel Labath     size_t bytes_read = ReadFromConnection(
327c4063eeeSPavel Labath         buf, sizeof(buf), std::chrono::seconds(5), status, &error);
328769d7041SPavel Labath     if (bytes_read > 0 || status == eConnectionStatusEndOfFile)
329*d0810779SPavel Labath       AppendBytesToCache(buf, bytes_read, true, status);
33030fdc8d8SChris Lattner 
331b9c1b51eSKate Stone     switch (status) {
33230fdc8d8SChris Lattner     case eConnectionStatusSuccess:
33330fdc8d8SChris Lattner       break;
33430fdc8d8SChris Lattner 
3357788e5fdSGreg Clayton     case eConnectionStatusEndOfFile:
3369fd5850fSCaroline Tice       done = true;
337*d0810779SPavel Labath       disconnect = GetCloseOnEOF();
3389fd5850fSCaroline Tice       break;
33942628281STodd Fiala     case eConnectionStatusError: // Check GetError() for details
340b9c1b51eSKate Stone       if (error.GetType() == eErrorTypePOSIX && error.GetError() == EIO) {
34142628281STodd Fiala         // EIO on a pipe is usually caused by remote shutdown
342*d0810779SPavel Labath         disconnect = GetCloseOnEOF();
34342628281STodd Fiala         done = true;
34442628281STodd Fiala       }
34533aba3c2SZachary Turner       if (error.Fail())
34633aba3c2SZachary Turner         LLDB_LOG(log, "error: {0}, status = {1}", error,
347a4a08442SRaphael Isemann                  Communication::ConnectionStatusAsString(status));
34842628281STodd Fiala       break;
349b9c1b51eSKate Stone     case eConnectionStatusInterrupted: // Synchronization signal from
350b9c1b51eSKate Stone                                        // SynchronizeWithReadThread()
351b9c1b51eSKate Stone       // The connection returns eConnectionStatusInterrupted only when there is
35205097246SAdrian Prantl       // no input pending to be read, so we can signal that.
353*d0810779SPavel Labath       BroadcastEvent(eBroadcastBitNoMorePendingInput);
3543f5df53fSPavel Labath       break;
35530fdc8d8SChris Lattner     case eConnectionStatusNoConnection:   // No connection
356b9c1b51eSKate Stone     case eConnectionStatusLostConnection: // Lost connection while connected to
357b9c1b51eSKate Stone                                           // a valid connection
35830fdc8d8SChris Lattner       done = true;
35962e0681aSJason Molenda       LLVM_FALLTHROUGH;
36030fdc8d8SChris Lattner     case eConnectionStatusTimedOut: // Request timed out
36133aba3c2SZachary Turner       if (error.Fail())
36233aba3c2SZachary Turner         LLDB_LOG(log, "error: {0}, status = {1}", error,
363a4a08442SRaphael Isemann                  Communication::ConnectionStatusAsString(status));
36430fdc8d8SChris Lattner       break;
36530fdc8d8SChris Lattner     }
36630fdc8d8SChris Lattner   }
367a007a6d8SPavel Labath   log = GetLog(LLDBLog::Communication);
368*d0810779SPavel Labath   LLDB_LOG(log, "Communication({0}) thread exiting...", this);
36930fdc8d8SChris Lattner 
370a9406daaSPavel Labath   // Handle threads wishing to synchronize with us.
371769d7041SPavel Labath   {
372a9406daaSPavel Labath     // Prevent new ones from showing up.
373*d0810779SPavel Labath     m_read_thread_did_exit = true;
374a9406daaSPavel Labath 
375a9406daaSPavel Labath     // Unblock any existing thread waiting for the synchronization signal.
376*d0810779SPavel Labath     BroadcastEvent(eBroadcastBitNoMorePendingInput);
377a9406daaSPavel Labath 
378a9406daaSPavel Labath     // Wait for the thread to finish...
379*d0810779SPavel Labath     std::lock_guard<std::mutex> guard(m_synchronize_mutex);
380a9406daaSPavel Labath     // ... and disconnect.
381769d7041SPavel Labath     if (disconnect)
382*d0810779SPavel Labath       Disconnect();
383769d7041SPavel Labath   }
384769d7041SPavel Labath 
385769d7041SPavel Labath   // Let clients know that this thread is exiting
386*d0810779SPavel Labath   BroadcastEvent(eBroadcastBitReadThreadDidExit);
38785200645SKonrad Kleine   return {};
38830fdc8d8SChris Lattner }
38930fdc8d8SChris Lattner 
SetReadThreadBytesReceivedCallback(ReadThreadBytesReceived callback,void * callback_baton)390b9c1b51eSKate Stone void Communication::SetReadThreadBytesReceivedCallback(
391b9c1b51eSKate Stone     ReadThreadBytesReceived callback, void *callback_baton) {
39230fdc8d8SChris Lattner   m_callback = callback;
39330fdc8d8SChris Lattner   m_callback_baton = callback_baton;
39430fdc8d8SChris Lattner }
39530fdc8d8SChris Lattner 
SynchronizeWithReadThread()396b9c1b51eSKate Stone void Communication::SynchronizeWithReadThread() {
3973f5df53fSPavel Labath   // Only one thread can do the synchronization dance at a time.
39816ff8604SSaleem Abdulrasool   std::lock_guard<std::mutex> guard(m_synchronize_mutex);
3993f5df53fSPavel Labath 
4003f5df53fSPavel Labath   // First start listening for the synchronization event.
401b9c1b51eSKate Stone   ListenerSP listener_sp(
402b9c1b51eSKate Stone       Listener::MakeListener("Communication::SyncronizeWithReadThread"));
403583bbb1dSJim Ingham   listener_sp->StartListeningForEvents(this, eBroadcastBitNoMorePendingInput);
4043f5df53fSPavel Labath 
4053f5df53fSPavel Labath   // If the thread is not running, there is no point in synchronizing.
4063f5df53fSPavel Labath   if (!m_read_thread_enabled || m_read_thread_did_exit)
4073f5df53fSPavel Labath     return;
4083f5df53fSPavel Labath 
4093f5df53fSPavel Labath   // Notify the read thread.
4103f5df53fSPavel Labath   m_connection_sp->InterruptRead();
4113f5df53fSPavel Labath 
4123f5df53fSPavel Labath   // Wait for the synchronization event.
4133f5df53fSPavel Labath   EventSP event_sp;
414d35031e1SPavel Labath   listener_sp->GetEvent(event_sp, llvm::None);
4153f5df53fSPavel Labath }
4163f5df53fSPavel Labath 
SetConnection(std::unique_ptr<Connection> connection)417451741a9SPavel Labath void Communication::SetConnection(std::unique_ptr<Connection> connection) {
418896ddd03SEugene Zelenko   Disconnect(nullptr);
419896ddd03SEugene Zelenko   StopReadThread(nullptr);
420451741a9SPavel Labath   m_connection_sp = std::move(connection);
42130fdc8d8SChris Lattner }
422ceb6b139SCaroline Tice 
423a4a08442SRaphael Isemann std::string
ConnectionStatusAsString(lldb::ConnectionStatus status)424a4a08442SRaphael Isemann Communication::ConnectionStatusAsString(lldb::ConnectionStatus status) {
425b9c1b51eSKate Stone   switch (status) {
426b9c1b51eSKate Stone   case eConnectionStatusSuccess:
427b9c1b51eSKate Stone     return "success";
428b9c1b51eSKate Stone   case eConnectionStatusError:
429b9c1b51eSKate Stone     return "error";
430b9c1b51eSKate Stone   case eConnectionStatusTimedOut:
431b9c1b51eSKate Stone     return "timed out";
432b9c1b51eSKate Stone   case eConnectionStatusNoConnection:
433b9c1b51eSKate Stone     return "no connection";
434b9c1b51eSKate Stone   case eConnectionStatusLostConnection:
435b9c1b51eSKate Stone     return "lost connection";
436b9c1b51eSKate Stone   case eConnectionStatusEndOfFile:
437b9c1b51eSKate Stone     return "end of file";
438b9c1b51eSKate Stone   case eConnectionStatusInterrupted:
439b9c1b51eSKate Stone     return "interrupted";
440ceb6b139SCaroline Tice   }
441ceb6b139SCaroline Tice 
442a4a08442SRaphael Isemann   return "@" + std::to_string(status);
443ceb6b139SCaroline Tice }
444