Coverage Report

Created: 2022-01-18 06:27

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Core/Communication.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- Communication.cpp -------------------------------------------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "lldb/Core/Communication.h"
10
11
#include "lldb/Host/HostThread.h"
12
#include "lldb/Host/ThreadLauncher.h"
13
#include "lldb/Utility/Connection.h"
14
#include "lldb/Utility/ConstString.h"
15
#include "lldb/Utility/Event.h"
16
#include "lldb/Utility/Listener.h"
17
#include "lldb/Utility/Log.h"
18
#include "lldb/Utility/Logging.h"
19
#include "lldb/Utility/Status.h"
20
21
#include "llvm/ADT/None.h"
22
#include "llvm/ADT/Optional.h"
23
#include "llvm/Support/Compiler.h"
24
25
#include <algorithm>
26
#include <chrono>
27
#include <cstring>
28
#include <memory>
29
30
#include <cerrno>
31
#include <cinttypes>
32
#include <cstdio>
33
34
using namespace lldb;
35
using namespace lldb_private;
36
37
0
ConstString &Communication::GetStaticBroadcasterClass() {
38
0
  static ConstString class_name("lldb.communication");
39
0
  return class_name;
40
0
}
41
42
Communication::Communication(const char *name)
43
    : Broadcaster(nullptr, name), m_connection_sp(),
44
      m_read_thread_enabled(false), m_read_thread_did_exit(false), m_bytes(),
45
      m_bytes_mutex(), m_write_mutex(), m_synchronize_mutex(),
46
      m_callback(nullptr), m_callback_baton(nullptr), m_close_on_eof(true)
47
48
11.4k
{
49
50
11.4k
  LLDB_LOG(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_OBJECT |
51
11.4k
                                                  LIBLLDB_LOG_COMMUNICATION),
52
11.4k
           "{0} Communication::Communication (name = {1})", this, name);
53
54
11.4k
  SetEventName(eBroadcastBitDisconnected, "disconnected");
55
11.4k
  SetEventName(eBroadcastBitReadThreadGotBytes, "got bytes");
56
11.4k
  SetEventName(eBroadcastBitReadThreadDidExit, "read thread did exit");
57
11.4k
  SetEventName(eBroadcastBitReadThreadShouldExit, "read thread should exit");
58
11.4k
  SetEventName(eBroadcastBitPacketAvailable, "packet available");
59
11.4k
  SetEventName(eBroadcastBitNoMorePendingInput, "no more pending input");
60
61
11.4k
  CheckInWithManager();
62
11.4k
}
63
64
11.1k
Communication::~Communication() {
65
11.1k
  LLDB_LOG(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_OBJECT |
66
11.1k
                                                  LIBLLDB_LOG_COMMUNICATION),
67
11.1k
           "{0} Communication::~Communication (name = {1})", this,
68
11.1k
           GetBroadcasterName().AsCString());
69
11.1k
  Clear();
70
11.1k
}
71
72
13.8k
void Communication::Clear() {
73
13.8k
  SetReadThreadBytesReceivedCallback(nullptr, nullptr);
74
13.8k
  StopReadThread(nullptr);
75
13.8k
  Disconnect(nullptr);
76
13.8k
}
77
78
16
ConnectionStatus Communication::Connect(const char *url, Status *error_ptr) {
79
16
  Clear();
80
81
16
  LLDB_LOG(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_COMMUNICATION),
82
16
           "{0} Communication::Connect (url = {1})", this, url);
83
84
16
  lldb::ConnectionSP connection_sp(m_connection_sp);
85
16
  if (connection_sp)
86
16
    return connection_sp->Connect(url, error_ptr);
87
0
  if (error_ptr)
88
0
    error_ptr->SetErrorString("Invalid connection.");
89
0
  return eConnectionStatusNoConnection;
90
16
}
91
92
43.4k
ConnectionStatus Communication::Disconnect(Status *error_ptr) {
93
43.4k
  LLDB_LOG(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_COMMUNICATION),
94
43.4k
           "{0} Communication::Disconnect ()", this);
95
96
43.4k
  assert((!m_read_thread_enabled || m_read_thread_did_exit) &&
97
43.4k
         "Disconnecting while the read thread is running is racy!");
98
0
  lldb::ConnectionSP connection_sp(m_connection_sp);
99
43.4k
  if (connection_sp) {
100
28.4k
    ConnectionStatus status = connection_sp->Disconnect(error_ptr);
101
    // We currently don't protect connection_sp with any mutex for multi-
102
    // threaded environments. So lets not nuke our connection class without
103
    // putting some multi-threaded protections in. We also probably don't want
104
    // to pay for the overhead it might cause if every time we access the
105
    // connection we have to take a lock.
106
    //
107
    // This unique pointer will cleanup after itself when this object goes
108
    // away, so there is no need to currently have it destroy itself
109
    // immediately upon disconnect.
110
    // connection_sp.reset();
111
28.4k
    return status;
112
28.4k
  }
113
14.9k
  return eConnectionStatusNoConnection;
114
43.4k
}
115
116
2.07M
bool Communication::IsConnected() const {
117
2.07M
  lldb::ConnectionSP connection_sp(m_connection_sp);
118
2.07M
  return (connection_sp ? 
connection_sp->IsConnected()2.06M
:
false2.73k
);
119
2.07M
}
120
121
0
bool Communication::HasConnection() const {
122
0
  return m_connection_sp.get() != nullptr;
123
0
}
124
125
size_t Communication::Read(void *dst, size_t dst_len,
126
                           const Timeout<std::micro> &timeout,
127
841k
                           ConnectionStatus &status, Status *error_ptr) {
128
841k
  Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_COMMUNICATION);
129
841k
  LLDB_LOG(
130
841k
      log,
131
841k
      "this = {0}, dst = {1}, dst_len = {2}, timeout = {3}, connection = {4}",
132
841k
      this, dst, dst_len, timeout, m_connection_sp.get());
133
134
841k
  if (m_read_thread_enabled) {
135
    // We have a dedicated read thread that is getting data for us
136
0
    size_t cached_bytes = GetCachedBytes(dst, dst_len);
137
0
    if (cached_bytes > 0 || (timeout && timeout->count() == 0)) {
138
0
      status = eConnectionStatusSuccess;
139
0
      return cached_bytes;
140
0
    }
141
142
0
    if (!m_connection_sp) {
143
0
      if (error_ptr)
144
0
        error_ptr->SetErrorString("Invalid connection.");
145
0
      status = eConnectionStatusNoConnection;
146
0
      return 0;
147
0
    }
148
149
0
    ListenerSP listener_sp(Listener::MakeListener("Communication::Read"));
150
0
    listener_sp->StartListeningForEvents(
151
0
        this, eBroadcastBitReadThreadGotBytes | eBroadcastBitReadThreadDidExit);
152
0
    EventSP event_sp;
153
0
    while (listener_sp->GetEvent(event_sp, timeout)) {
154
0
      const uint32_t event_type = event_sp->GetType();
155
0
      if (event_type & eBroadcastBitReadThreadGotBytes) {
156
0
        return GetCachedBytes(dst, dst_len);
157
0
      }
158
159
0
      if (event_type & eBroadcastBitReadThreadDidExit) {
160
0
        if (GetCloseOnEOF())
161
0
          Disconnect(nullptr);
162
0
        break;
163
0
      }
164
0
    }
165
0
    return 0;
166
0
  }
167
168
  // We aren't using a read thread, just read the data synchronously in this
169
  // thread.
170
841k
  return ReadFromConnection(dst, dst_len, timeout, status, error_ptr);
171
841k
}
172
173
size_t Communication::Write(const void *src, size_t src_len,
174
419k
                            ConnectionStatus &status, Status *error_ptr) {
175
419k
  lldb::ConnectionSP connection_sp(m_connection_sp);
176
177
419k
  std::lock_guard<std::mutex> guard(m_write_mutex);
178
419k
  LLDB_LOG(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_COMMUNICATION),
179
419k
           "{0} Communication::Write (src = {1}, src_len = {2}"
180
419k
           ") connection = {3}",
181
419k
           this, src, (uint64_t)src_len, connection_sp.get());
182
183
419k
  if (connection_sp)
184
419k
    return connection_sp->Write(src, src_len, status, error_ptr);
185
186
0
  if (error_ptr)
187
0
    error_ptr->SetErrorString("Invalid connection.");
188
0
  status = eConnectionStatusNoConnection;
189
0
  return 0;
190
419k
}
191
192
size_t Communication::WriteAll(const void *src, size_t src_len,
193
419k
                               ConnectionStatus &status, Status *error_ptr) {
194
419k
  size_t total_written = 0;
195
419k
  do
196
419k
    total_written += Write(static_cast<const char *>(src) + total_written,
197
419k
                           src_len - total_written, status, error_ptr);
198
419k
  while (status == eConnectionStatusSuccess && total_written < src_len);
199
419k
  return total_written;
200
419k
}
201
202
2.64k
bool Communication::StartReadThread(Status *error_ptr) {
203
2.64k
  if (error_ptr)
204
0
    error_ptr->Clear();
205
206
2.64k
  if (m_read_thread.IsJoinable())
207
0
    return true;
208
209
2.64k
  LLDB_LOG(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_COMMUNICATION),
210
2.64k
           "{0} Communication::StartReadThread ()", this);
211
212
2.64k
  const std::string thread_name =
213
2.64k
      llvm::formatv("<lldb.comm.{0}>", GetBroadcasterName());
214
215
2.64k
  m_read_thread_enabled = true;
216
2.64k
  m_read_thread_did_exit = false;
217
2.64k
  auto maybe_thread = ThreadLauncher::LaunchThread(
218
2.64k
      thread_name, Communication::ReadThread, this);
219
2.64k
  if (maybe_thread) {
220
2.64k
    m_read_thread = *maybe_thread;
221
2.64k
  } else {
222
0
    if (error_ptr)
223
0
      *error_ptr = Status(maybe_thread.takeError());
224
0
    else {
225
0
      LLDB_LOG(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST),
226
0
               "failed to launch host thread: {}",
227
0
               llvm::toString(maybe_thread.takeError()));
228
0
    }
229
0
  }
230
231
2.64k
  if (!m_read_thread.IsJoinable())
232
0
    m_read_thread_enabled = false;
233
234
2.64k
  return m_read_thread_enabled;
235
2.64k
}
236
237
27.5k
bool Communication::StopReadThread(Status *error_ptr) {
238
27.5k
  if (!m_read_thread.IsJoinable())
239
24.9k
    return true;
240
241
2.56k
  LLDB_LOG(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_COMMUNICATION),
242
2.56k
           "{0} Communication::StopReadThread ()", this);
243
244
2.56k
  m_read_thread_enabled = false;
245
246
2.56k
  BroadcastEvent(eBroadcastBitReadThreadShouldExit, nullptr);
247
248
  // error = m_read_thread.Cancel();
249
250
2.56k
  Status error = m_read_thread.Join(nullptr);
251
2.56k
  return error.Success();
252
27.5k
}
253
254
82
bool Communication::JoinReadThread(Status *error_ptr) {
255
82
  if (!m_read_thread.IsJoinable())
256
0
    return true;
257
258
82
  Status error = m_read_thread.Join(nullptr);
259
82
  return error.Success();
260
82
}
261
262
0
size_t Communication::GetCachedBytes(void *dst, size_t dst_len) {
263
0
  std::lock_guard<std::recursive_mutex> guard(m_bytes_mutex);
264
0
  if (!m_bytes.empty()) {
265
    // If DST is nullptr and we have a thread, then return the number of bytes
266
    // that are available so the caller can call again
267
0
    if (dst == nullptr)
268
0
      return m_bytes.size();
269
270
0
    const size_t len = std::min<size_t>(dst_len, m_bytes.size());
271
272
0
    ::memcpy(dst, m_bytes.c_str(), len);
273
0
    m_bytes.erase(m_bytes.begin(), m_bytes.begin() + len);
274
275
0
    return len;
276
0
  }
277
0
  return 0;
278
0
}
279
280
void Communication::AppendBytesToCache(const uint8_t *bytes, size_t len,
281
                                       bool broadcast,
282
5.05k
                                       ConnectionStatus status) {
283
5.05k
  LLDB_LOG(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_COMMUNICATION),
284
5.05k
           "{0} Communication::AppendBytesToCache (src = {1}, src_len = {2}, "
285
5.05k
           "broadcast = {3})",
286
5.05k
           this, bytes, (uint64_t)len, broadcast);
287
5.05k
  if ((bytes == nullptr || len == 0) &&
288
5.05k
      
(status != lldb::eConnectionStatusEndOfFile)2.64k
)
289
0
    return;
290
5.05k
  if (m_callback) {
291
    // If the user registered a callback, then call it and do not broadcast
292
5.05k
    m_callback(m_callback_baton, bytes, len);
293
5.05k
  } else 
if (1
bytes != nullptr1
&&
len > 01
) {
294
0
    std::lock_guard<std::recursive_mutex> guard(m_bytes_mutex);
295
0
    m_bytes.append((const char *)bytes, len);
296
0
    if (broadcast)
297
0
      BroadcastEventIfUnique(eBroadcastBitReadThreadGotBytes);
298
0
  }
299
5.05k
}
300
301
size_t Communication::ReadFromConnection(void *dst, size_t dst_len,
302
                                         const Timeout<std::micro> &timeout,
303
                                         ConnectionStatus &status,
304
866k
                                         Status *error_ptr) {
305
866k
  lldb::ConnectionSP connection_sp(m_connection_sp);
306
866k
  if (connection_sp)
307
866k
    return connection_sp->Read(dst, dst_len, timeout, status, error_ptr);
308
309
0
  if (error_ptr)
310
0
    error_ptr->SetErrorString("Invalid connection.");
311
0
  status = eConnectionStatusNoConnection;
312
0
  return 0;
313
866k
}
314
315
0
bool Communication::ReadThreadIsRunning() { return m_read_thread_enabled; }
316
317
2.64k
lldb::thread_result_t Communication::ReadThread(lldb::thread_arg_t p) {
318
2.64k
  Communication *comm = (Communication *)p;
319
320
2.64k
  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_COMMUNICATION));
321
322
2.64k
  LLDB_LOGF(log, "%p Communication::ReadThread () thread starting...", p);
323
324
2.64k
  uint8_t buf[1024];
325
326
2.64k
  Status error;
327
2.64k
  ConnectionStatus status = eConnectionStatusSuccess;
328
2.64k
  bool done = false;
329
2.64k
  bool disconnect = false;
330
26.9k
  while (!done && 
comm->m_read_thread_enabled24.3k
) {
331
24.3k
    size_t bytes_read = comm->ReadFromConnection(
332
24.3k
        buf, sizeof(buf), std::chrono::seconds(5), status, &error);
333
24.3k
    if (bytes_read > 0 || 
status == eConnectionStatusEndOfFile21.9k
)
334
5.05k
      comm->AppendBytesToCache(buf, bytes_read, true, status);
335
336
24.3k
    switch (status) {
337
2.40k
    case eConnectionStatusSuccess:
338
2.40k
      break;
339
340
2.64k
    case eConnectionStatusEndOfFile:
341
2.64k
      done = true;
342
2.64k
      disconnect = comm->GetCloseOnEOF();
343
2.64k
      break;
344
0
    case eConnectionStatusError: // Check GetError() for details
345
0
      if (error.GetType() == eErrorTypePOSIX && error.GetError() == EIO) {
346
        // EIO on a pipe is usually caused by remote shutdown
347
0
        disconnect = comm->GetCloseOnEOF();
348
0
        done = true;
349
0
      }
350
0
      if (error.Fail())
351
0
        LLDB_LOG(log, "error: {0}, status = {1}", error,
352
0
                 Communication::ConnectionStatusAsString(status));
353
0
      break;
354
19.2k
    case eConnectionStatusInterrupted: // Synchronization signal from
355
                                       // SynchronizeWithReadThread()
356
      // The connection returns eConnectionStatusInterrupted only when there is
357
      // no input pending to be read, so we can signal that.
358
19.2k
      comm->BroadcastEvent(eBroadcastBitNoMorePendingInput);
359
19.2k
      break;
360
0
    case eConnectionStatusNoConnection:   // No connection
361
0
    case eConnectionStatusLostConnection: // Lost connection while connected to
362
                                          // a valid connection
363
0
      done = true;
364
0
      LLVM_FALLTHROUGH;
365
29
    case eConnectionStatusTimedOut: // Request timed out
366
29
      if (error.Fail())
367
29
        LLDB_LOG(log, "error: {0}, status = {1}", error,
368
29
                 Communication::ConnectionStatusAsString(status));
369
29
      break;
370
24.3k
    }
371
24.3k
  }
372
2.64k
  log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_COMMUNICATION);
373
2.64k
  if (log)
374
0
    LLDB_LOGF(log, "%p Communication::ReadThread () thread exiting...", p);
375
376
  // Handle threads wishing to synchronize with us.
377
2.64k
  {
378
    // Prevent new ones from showing up.
379
2.64k
    comm->m_read_thread_did_exit = true;
380
381
    // Unblock any existing thread waiting for the synchronization signal.
382
2.64k
    comm->BroadcastEvent(eBroadcastBitNoMorePendingInput);
383
384
    // Wait for the thread to finish...
385
2.64k
    std::lock_guard<std::mutex> guard(comm->m_synchronize_mutex);
386
    // ... and disconnect.
387
2.64k
    if (disconnect)
388
2.64k
      comm->Disconnect();
389
2.64k
  }
390
391
  // Let clients know that this thread is exiting
392
2.64k
  comm->BroadcastEvent(eBroadcastBitReadThreadDidExit);
393
2.64k
  return {};
394
2.64k
}
395
396
void Communication::SetReadThreadBytesReceivedCallback(
397
16.5k
    ReadThreadBytesReceived callback, void *callback_baton) {
398
16.5k
  m_callback = callback;
399
16.5k
  m_callback_baton = callback_baton;
400
16.5k
}
401
402
22.2k
void Communication::SynchronizeWithReadThread() {
403
  // Only one thread can do the synchronization dance at a time.
404
22.2k
  std::lock_guard<std::mutex> guard(m_synchronize_mutex);
405
406
  // First start listening for the synchronization event.
407
22.2k
  ListenerSP listener_sp(
408
22.2k
      Listener::MakeListener("Communication::SyncronizeWithReadThread"));
409
22.2k
  listener_sp->StartListeningForEvents(this, eBroadcastBitNoMorePendingInput);
410
411
  // If the thread is not running, there is no point in synchronizing.
412
22.2k
  if (!m_read_thread_enabled || 
m_read_thread_did_exit21.7k
)
413
3.00k
    return;
414
415
  // Notify the read thread.
416
19.2k
  m_connection_sp->InterruptRead();
417
418
  // Wait for the synchronization event.
419
19.2k
  EventSP event_sp;
420
19.2k
  listener_sp->GetEvent(event_sp, llvm::None);
421
19.2k
}
422
423
5.38k
void Communication::SetConnection(std::unique_ptr<Connection> connection) {
424
5.38k
  Disconnect(nullptr);
425
5.38k
  StopReadThread(nullptr);
426
5.38k
  m_connection_sp = std::move(connection);
427
5.38k
}
428
429
std::string
430
0
Communication::ConnectionStatusAsString(lldb::ConnectionStatus status) {
431
0
  switch (status) {
432
0
  case eConnectionStatusSuccess:
433
0
    return "success";
434
0
  case eConnectionStatusError:
435
0
    return "error";
436
0
  case eConnectionStatusTimedOut:
437
0
    return "timed out";
438
0
  case eConnectionStatusNoConnection:
439
0
    return "no connection";
440
0
  case eConnectionStatusLostConnection:
441
0
    return "lost connection";
442
0
  case eConnectionStatusEndOfFile:
443
0
    return "end of file";
444
0
  case eConnectionStatusInterrupted:
445
0
    return "interrupted";
446
0
  }
447
448
0
  return "@" + std::to_string(status);
449
0
}