GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/inspector/main_thread_interface.cc Lines: 183 184 99.5 %
Date: 2019-02-13 22:28:58 Branches: 38 62 61.3 %

Line Branch Exec Source
1
#include "main_thread_interface.h"
2
3
#include "node_mutex.h"
4
#include "v8-inspector.h"
5
6
#include <functional>
7
#include <unicode/unistr.h>
8
#include "util-inl.h"
9
10
namespace node {
11
namespace inspector {
12
namespace {
13
14
using v8_inspector::StringView;
15
using v8_inspector::StringBuffer;
16
17
template <typename T>
18
class DeletableWrapper : public Deletable {
19
 public:
20
21
  explicit DeletableWrapper(std::unique_ptr<T> object)
21
21
                        : object_(std::move(object)) {}
22

42
  ~DeletableWrapper() override = default;
23
24
228
  static T* get(MainThreadInterface* thread, int id) {
25
    return
26
228
        static_cast<DeletableWrapper<T>*>(thread->GetObject(id))->object_.get();
27
  }
28
29
 private:
30
  std::unique_ptr<T> object_;
31
};
32
33
template <typename T>
34
21
std::unique_ptr<Deletable> WrapInDeletable(std::unique_ptr<T> object) {
35
  return std::unique_ptr<DeletableWrapper<T>>(
36
21
      new DeletableWrapper<T>(std::move(object)));
37
}
38
39
template <typename Factory>
40
34
class CreateObjectRequest : public Request {
41
 public:
42
17
  CreateObjectRequest(int object_id, Factory factory)
43
17
                      : object_id_(object_id), factory_(std::move(factory)) {}
44
45
17
  void Call(MainThreadInterface* thread) {
46
17
    thread->AddObject(object_id_, WrapInDeletable(factory_(thread)));
47
17
  }
48
49
 private:
50
  int object_id_;
51
  Factory factory_;
52
};
53
54
template <typename Factory>
55
17
std::unique_ptr<Request> NewCreateRequest(int object_id, Factory factory) {
56
  return std::unique_ptr<Request>(
57
17
      new CreateObjectRequest<Factory>(object_id, std::move(factory)));
58
}
59
60
42
class DeleteRequest : public Request {
61
 public:
62
21
  explicit DeleteRequest(int object_id) : object_id_(object_id) {}
63
64
17
  void Call(MainThreadInterface* thread) override {
65
17
    thread->RemoveObject(object_id_);
66
17
  }
67
68
 private:
69
  int object_id_;
70
};
71
72
template <typename Target, typename Fn>
73

456
class CallRequest : public Request {
74
 public:
75
228
  CallRequest(int id, Fn fn) : id_(id), fn_(std::move(fn)) {}
76
77
228
  void Call(MainThreadInterface* thread) override {
78
228
    fn_(DeletableWrapper<Target>::get(thread, id_));
79
228
  }
80
81
 private:
82
  int id_;
83
  Fn fn_;
84
};
85
86
18258
class DispatchMessagesTask : public v8::Task {
87
 public:
88
9743
  explicit DispatchMessagesTask(MainThreadInterface* thread)
89
9743
                                : thread_(thread) {}
90
91
9132
  void Run() override {
92
9132
    thread_->DispatchMessages();
93
9132
  }
94
95
 private:
96
  MainThreadInterface* thread_;
97
};
98
99
151
void DisposePairCallback(uv_handle_t* ref) {
100
  using AsyncAndInterface = std::pair<uv_async_t, MainThreadInterface*>;
101
  AsyncAndInterface* pair = node::ContainerOf(
102
151
      &AsyncAndInterface::first, reinterpret_cast<uv_async_t*>(ref));
103
151
  delete pair;
104
151
}
105
106
template <typename T>
107
class AnotherThreadObjectReference {
108
 public:
109
21
  AnotherThreadObjectReference(
110
      std::shared_ptr<MainThreadHandle> thread, int object_id)
111
21
      : thread_(thread), object_id_(object_id) {}
112
113
  template <typename Factory>
114
17
  AnotherThreadObjectReference(
115
      std::shared_ptr<MainThreadHandle> thread, Factory factory)
116
17
      : AnotherThreadObjectReference(thread, thread->newObjectId()) {
117
17
    thread_->Post(NewCreateRequest(object_id_, std::move(factory)));
118
17
  }
119
  AnotherThreadObjectReference(AnotherThreadObjectReference&) = delete;
120
121
21
  ~AnotherThreadObjectReference() {
122
    // Disappearing thread may cause a memory leak
123
21
    thread_->Post(
124
42
        std::unique_ptr<DeleteRequest>(new DeleteRequest(object_id_)));
125
21
  }
126
127
  template <typename Fn>
128
228
  void Call(Fn fn) const {
129
    using Request = CallRequest<T, Fn>;
130
228
    thread_->Post(std::unique_ptr<Request>(
131
228
        new Request(object_id_, std::move(fn))));
132
228
  }
133
134
  template <typename Arg>
135
136
  void Call(void (T::*fn)(Arg), Arg argument) const {
136
136
    Call(std::bind(Apply<Arg>, std::placeholders::_1, fn, std::move(argument)));
137
136
  }
138
139
 private:
140
  // This has to use non-const reference to support std::bind with non-copyable
141
  // types
142
  template <typename Argument>
143
136
  static void Apply(T* target, void (T::*fn)(Argument),
144
    /* NOLINT (runtime/references) */ Argument& argument) {
145

136
    (target->*fn)(std::move(argument));
146
136
  }
147
148
  std::shared_ptr<MainThreadHandle> thread_;
149
  const int object_id_;
150
};
151
152
17
class MainThreadSessionState {
153
 public:
154
17
  MainThreadSessionState(MainThreadInterface* thread, bool prevent_shutdown)
155
                         : thread_(thread),
156
17
                           prevent_shutdown_(prevent_shutdown) {}
157
158
17
  static std::unique_ptr<MainThreadSessionState> Create(
159
      MainThreadInterface* thread, bool prevent_shutdown) {
160
    return std::unique_ptr<MainThreadSessionState>(
161
17
        new MainThreadSessionState(thread, prevent_shutdown));
162
  }
163
164
17
  void Connect(std::unique_ptr<InspectorSessionDelegate> delegate) {
165
17
    Agent* agent = thread_->inspector_agent();
166
17
    if (agent != nullptr)
167
17
      session_ = agent->Connect(std::move(delegate), prevent_shutdown_);
168
17
  }
169
170
119
  void Dispatch(std::unique_ptr<StringBuffer> message) {
171
119
    session_->Dispatch(message->string());
172
119
  }
173
174
 private:
175
  MainThreadInterface* thread_;
176
  bool prevent_shutdown_;
177
  std::unique_ptr<InspectorSession> session_;
178
};
179
180
34
class CrossThreadInspectorSession : public InspectorSession {
181
 public:
182
17
  CrossThreadInspectorSession(
183
      int id,
184
      std::shared_ptr<MainThreadHandle> thread,
185
      std::unique_ptr<InspectorSessionDelegate> delegate,
186
      bool prevent_shutdown)
187
      : state_(thread, std::bind(MainThreadSessionState::Create,
188
                                 std::placeholders::_1,
189
17
                                 prevent_shutdown)) {
190
17
    state_.Call(&MainThreadSessionState::Connect, std::move(delegate));
191
17
  }
192
193
119
  void Dispatch(const StringView& message) override {
194
    state_.Call(&MainThreadSessionState::Dispatch,
195
119
                StringBuffer::create(message));
196
119
  }
197
198
 private:
199
  AnotherThreadObjectReference<MainThreadSessionState> state_;
200
};
201
202
8
class ThreadSafeDelegate : public InspectorSessionDelegate {
203
 public:
204
4
  ThreadSafeDelegate(std::shared_ptr<MainThreadHandle> thread, int object_id)
205
4
                     : thread_(thread), delegate_(thread, object_id) {}
206
207
92
  void SendMessageToFrontend(const v8_inspector::StringView& message) override {
208
    delegate_.Call(
209
460
        [m = StringBuffer::create(message)]
210
92
        (InspectorSessionDelegate* delegate) {
211
92
      delegate->SendMessageToFrontend(m->string());
212
184
    });
213
92
  }
214
215
 private:
216
  std::shared_ptr<MainThreadHandle> thread_;
217
  AnotherThreadObjectReference<InspectorSessionDelegate> delegate_;
218
};
219
}  // namespace
220
221
222
4415
MainThreadInterface::MainThreadInterface(Agent* agent, uv_loop_t* loop,
223
                                         v8::Isolate* isolate,
224
                                         v8::Platform* platform)
225
                                         : agent_(agent), isolate_(isolate),
226
4415
                                           platform_(platform) {
227
4415
  main_thread_request_.reset(new AsyncAndInterface(uv_async_t(), this));
228
4415
  CHECK_EQ(0, uv_async_init(loop, &main_thread_request_->first,
229
                            DispatchMessagesAsyncCallback));
230
  // Inspector uv_async_t should not prevent main loop shutdown.
231
4415
  uv_unref(reinterpret_cast<uv_handle_t*>(&main_thread_request_->first));
232
4415
}
233
234
8094
MainThreadInterface::~MainThreadInterface() {
235
4047
  if (handle_)
236
4047
    handle_->Reset();
237
4047
}
238
239
// static
240
6986
void MainThreadInterface::DispatchMessagesAsyncCallback(uv_async_t* async) {
241
  AsyncAndInterface* asyncAndInterface =
242
6986
      node::ContainerOf(&AsyncAndInterface::first, async);
243
6986
  asyncAndInterface->second->DispatchMessages();
244
6986
}
245
246
// static
247
4047
void MainThreadInterface::CloseAsync(AsyncAndInterface* pair) {
248
4047
  uv_close(reinterpret_cast<uv_handle_t*>(&pair->first), DisposePairCallback);
249
4047
}
250
251
9796
void MainThreadInterface::Post(std::unique_ptr<Request> request) {
252
9796
  Mutex::ScopedLock scoped_lock(requests_lock_);
253
9796
  bool needs_notify = requests_.empty();
254
9796
  requests_.push_back(std::move(request));
255
9796
  if (needs_notify) {
256
9743
    CHECK_EQ(0, uv_async_send(&main_thread_request_->first));
257

9743
    if (isolate_ != nullptr && platform_ != nullptr) {
258
      std::shared_ptr<v8::TaskRunner> taskrunner =
259
9743
        platform_->GetForegroundTaskRunner(isolate_);
260
9743
      taskrunner->PostTask(std::make_unique<DispatchMessagesTask>(this));
261
27097
      isolate_->RequestInterrupt([](v8::Isolate* isolate, void* thread) {
262
8678
        static_cast<MainThreadInterface*>(thread)->DispatchMessages();
263
36840
      }, this);
264
    }
265
  }
266
9796
  incoming_message_cond_.Broadcast(scoped_lock);
267
9796
}
268
269
86
bool MainThreadInterface::WaitForFrontendEvent() {
270
  // We allow DispatchMessages reentry as we enter the pause. This is important
271
  // to support debugging the code invoked by an inspector call, such
272
  // as Runtime.evaluate
273
86
  dispatching_messages_ = false;
274
86
  if (dispatching_message_queue_.empty()) {
275
86
    Mutex::ScopedLock scoped_lock(requests_lock_);
276
86
    while (requests_.empty()) incoming_message_cond_.Wait(scoped_lock);
277
  }
278
86
  return true;
279
}
280
281
24796
void MainThreadInterface::DispatchMessages() {
282
24796
  if (dispatching_messages_)
283
24916
    return;
284
24676
  dispatching_messages_ = true;
285
24676
  bool had_messages = false;
286
34418
  do {
287
34418
    if (dispatching_message_queue_.empty()) {
288
34418
      Mutex::ScopedLock scoped_lock(requests_lock_);
289
34418
      requests_.swap(dispatching_message_queue_);
290
    }
291
34418
    had_messages = !dispatching_message_queue_.empty();
292
78631
    while (!dispatching_message_queue_.empty()) {
293
9794
      MessageQueue::value_type task;
294
9794
      std::swap(dispatching_message_queue_.front(), task);
295
9794
      dispatching_message_queue_.pop_front();
296
9795
      task->Call(this);
297
9795
    }
298
  } while (had_messages);
299
24676
  dispatching_messages_ = false;
300
}
301
302
9256
std::shared_ptr<MainThreadHandle> MainThreadInterface::GetHandle() {
303
9256
  if (handle_ == nullptr)
304
4415
    handle_ = std::make_shared<MainThreadHandle>(this);
305
9256
  return handle_;
306
}
307
308
4638
void MainThreadInterface::AddObject(int id,
309
                                    std::unique_ptr<Deletable> object) {
310
4638
  CHECK_NOT_NULL(object);
311
4638
  managed_objects_[id] = std::move(object);
312
4639
}
313
314
4622
void MainThreadInterface::RemoveObject(int id) {
315
4622
  CHECK_EQ(1, managed_objects_.erase(id));
316
4622
}
317
318
228
Deletable* MainThreadInterface::GetObject(int id) {
319
228
  Deletable* pointer = GetObjectIfExists(id);
320
  // This would mean the object is requested after it was disposed, which is
321
  // a coding error.
322
228
  CHECK_NOT_NULL(pointer);
323
228
  return pointer;
324
}
325
326
232
Deletable* MainThreadInterface::GetObjectIfExists(int id) {
327
232
  auto iterator = managed_objects_.find(id);
328
232
  if (iterator == managed_objects_.end()) {
329
    return nullptr;
330
  }
331
232
  return iterator->second.get();
332
}
333
334
82352
std::unique_ptr<StringBuffer> Utf8ToStringView(const std::string& message) {
335
  icu::UnicodeString utf16 = icu::UnicodeString::fromUTF8(
336
82352
      icu::StringPiece(message.data(), message.length()));
337
82354
  StringView view(reinterpret_cast<const uint16_t*>(utf16.getBuffer()),
338
164708
                  utf16.length());
339
82352
  return StringBuffer::create(view);
340
}
341
342
17
std::unique_ptr<InspectorSession> MainThreadHandle::Connect(
343
    std::unique_ptr<InspectorSessionDelegate> delegate,
344
    bool prevent_shutdown) {
345
  return std::unique_ptr<InspectorSession>(
346
      new CrossThreadInspectorSession(++next_session_id_,
347
                                      shared_from_this(),
348
17
                                      std::move(delegate),
349
34
                                      prevent_shutdown));
350
}
351
352
9804
bool MainThreadHandle::Post(std::unique_ptr<Request> request) {
353
9804
  Mutex::ScopedLock scoped_lock(block_lock_);
354
9804
  if (!main_thread_)
355
8
    return false;
356
9796
  main_thread_->Post(std::move(request));
357
9796
  return true;
358
}
359
360
4047
void MainThreadHandle::Reset() {
361
4047
  Mutex::ScopedLock scoped_lock(block_lock_);
362
4047
  main_thread_ = nullptr;
363
4047
}
364
365
std::unique_ptr<InspectorSessionDelegate>
366
4
MainThreadHandle::MakeDelegateThreadSafe(
367
    std::unique_ptr<InspectorSessionDelegate> delegate) {
368
4
  int id = newObjectId();
369
4
  main_thread_->AddObject(id, WrapInDeletable(std::move(delegate)));
370
  return std::unique_ptr<InspectorSessionDelegate>(
371
4
      new ThreadSafeDelegate(shared_from_this(), id));
372
}
373
374
151
bool MainThreadHandle::Expired() {
375
151
  Mutex::ScopedLock scoped_lock(block_lock_);
376
151
  return main_thread_ == nullptr;
377
}
378
}  // namespace inspector
379
}  // namespace node