GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/node_platform.cc Lines: 350 361 97.0 %
Date: 2020-02-27 22:14:15 Branches: 83 108 76.9 %

Line Branch Exec Source
1
#include "node_platform.h"
2
#include "node_internals.h"
3
4
#include "env-inl.h"
5
#include "debug_utils-inl.h"
6
#include <algorithm>  // find_if(), find(), move()
7
#include <cmath>  // llround()
8
#include <memory>  // unique_ptr(), shared_ptr(), make_shared()
9
10
namespace node {
11
12
using v8::Isolate;
13
using v8::Object;
14
using v8::Platform;
15
using v8::Task;
16
using node::tracing::TracingController;
17
18
namespace {
19
20
struct PlatformWorkerData {
21
  TaskQueue<Task>* task_queue;
22
  Mutex* platform_workers_mutex;
23
  ConditionVariable* platform_workers_ready;
24
  int* pending_platform_workers;
25
  int id;
26
};
27
28
16407
static void PlatformWorkerThread(void* data) {
29
  std::unique_ptr<PlatformWorkerData>
30
32985
      worker_data(static_cast<PlatformWorkerData*>(data));
31
32
16560
  TaskQueue<Task>* pending_worker_tasks = worker_data->task_queue;
33

33051
  TRACE_EVENT_METADATA1("__metadata", "thread_name", "name",
34
                        "PlatformWorkerThread");
35
36
  // Notify the main thread that the platform worker is ready.
37
  {
38
33151
    Mutex::ScopedLock lock(*worker_data->platform_workers_mutex);
39
16598
    (*worker_data->pending_platform_workers)--;
40
16598
    worker_data->platform_workers_ready->Signal(lock);
41
  }
42
43
250534
  while (std::unique_ptr<Task> task = pending_worker_tasks->BlockingPop()) {
44
116644
    task->Run();
45
116626
    pending_worker_tasks->NotifyOfCompletion();
46
116971
  }
47
16578
}
48
49
}  // namespace
50
51
4143
class WorkerThreadsTaskRunner::DelayedTaskScheduler {
52
 public:
53
4148
  explicit DelayedTaskScheduler(TaskQueue<Task>* tasks)
54
4148
    : pending_worker_tasks_(tasks) {}
55
56
4148
  std::unique_ptr<uv_thread_t> Start() {
57
12444
    auto start_thread = [](void* data) {
58
4148
      static_cast<DelayedTaskScheduler*>(data)->Run();
59
12439
    };
60
4148
    std::unique_ptr<uv_thread_t> t { new uv_thread_t() };
61
4148
    uv_sem_init(&ready_, 0);
62
4148
    CHECK_EQ(0, uv_thread_create(t.get(), start_thread, this));
63
4148
    uv_sem_wait(&ready_);
64
4148
    uv_sem_destroy(&ready_);
65
4148
    return t;
66
  }
67
68
68
  void PostDelayedTask(std::unique_ptr<Task> task, double delay_in_seconds) {
69
204
    tasks_.Push(std::unique_ptr<Task>(new ScheduleTask(this, std::move(task),
70
136
                                                       delay_in_seconds)));
71
68
    uv_async_send(&flush_tasks_);
72
68
  }
73
74
4143
  void Stop() {
75
4143
    tasks_.Push(std::unique_ptr<Task>(new StopTask(this)));
76
4143
    uv_async_send(&flush_tasks_);
77
4143
  }
78
79
 private:
80
4148
  void Run() {
81

8296
    TRACE_EVENT_METADATA1("__metadata", "thread_name", "name",
82
                          "WorkerThreadsTaskRunner::DelayedTaskScheduler");
83
4148
    loop_.data = this;
84
4148
    CHECK_EQ(0, uv_loop_init(&loop_));
85
4148
    flush_tasks_.data = this;
86
4148
    CHECK_EQ(0, uv_async_init(&loop_, &flush_tasks_, FlushTasks));
87
4148
    uv_sem_post(&ready_);
88
89
4148
    uv_run(&loop_, UV_RUN_DEFAULT);
90
4143
    CheckedUvLoopClose(&loop_);
91
4143
  }
92
93
4208
  static void FlushTasks(uv_async_t* flush_tasks) {
94
    DelayedTaskScheduler* scheduler =
95
4208
        ContainerOf(&DelayedTaskScheduler::loop_, flush_tasks->loop);
96
12630
    while (std::unique_ptr<Task> task = scheduler->tasks_.Pop())
97
8422
      task->Run();
98
4208
  }
99
100
8286
  class StopTask : public Task {
101
   public:
102
4143
    explicit StopTask(DelayedTaskScheduler* scheduler): scheduler_(scheduler) {}
103
104
4143
    void Run() override {
105
8286
      std::vector<uv_timer_t*> timers;
106
4210
      for (uv_timer_t* timer : scheduler_->timers_)
107
67
        timers.push_back(timer);
108
4210
      for (uv_timer_t* timer : timers)
109
67
        scheduler_->TakeTimerTask(timer);
110
8286
      uv_close(reinterpret_cast<uv_handle_t*>(&scheduler_->flush_tasks_),
111
16572
               [](uv_handle_t* handle) {});
112
4143
    }
113
114
   private:
115
     DelayedTaskScheduler* scheduler_;
116
  };
117
118
136
  class ScheduleTask : public Task {
119
   public:
120
68
    ScheduleTask(DelayedTaskScheduler* scheduler,
121
                 std::unique_ptr<Task> task,
122
                 double delay_in_seconds)
123
68
      : scheduler_(scheduler),
124
68
        task_(std::move(task)),
125
136
        delay_in_seconds_(delay_in_seconds) {}
126
127
68
    void Run() override {
128
68
      uint64_t delay_millis = llround(delay_in_seconds_ * 1000);
129
136
      std::unique_ptr<uv_timer_t> timer(new uv_timer_t());
130
68
      CHECK_EQ(0, uv_timer_init(&scheduler_->loop_, timer.get()));
131
68
      timer->data = task_.release();
132
68
      CHECK_EQ(0, uv_timer_start(timer.get(), RunTask, delay_millis, 0));
133
68
      scheduler_->timers_.insert(timer.release());
134
68
    }
135
136
   private:
137
    DelayedTaskScheduler* scheduler_;
138
    std::unique_ptr<Task> task_;
139
    double delay_in_seconds_;
140
  };
141
142
1
  static void RunTask(uv_timer_t* timer) {
143
    DelayedTaskScheduler* scheduler =
144
1
        ContainerOf(&DelayedTaskScheduler::loop_, timer->loop);
145
1
    scheduler->pending_worker_tasks_->Push(scheduler->TakeTimerTask(timer));
146
1
  }
147
148
68
  std::unique_ptr<Task> TakeTimerTask(uv_timer_t* timer) {
149
68
    std::unique_ptr<Task> task(static_cast<Task*>(timer->data));
150
68
    uv_timer_stop(timer);
151
340
    uv_close(reinterpret_cast<uv_handle_t*>(timer), [](uv_handle_t* handle) {
152
68
      delete reinterpret_cast<uv_timer_t*>(handle);
153
272
    });
154
68
    timers_.erase(timer);
155
68
    return task;
156
  }
157
158
  uv_sem_t ready_;
159
  TaskQueue<Task>* pending_worker_tasks_;
160
161
  TaskQueue<Task> tasks_;
162
  uv_loop_t loop_;
163
  uv_async_t flush_tasks_;
164
  std::unordered_set<uv_timer_t*> timers_;
165
};
166
167
4148
WorkerThreadsTaskRunner::WorkerThreadsTaskRunner(int thread_pool_size) {
168
8296
  Mutex platform_workers_mutex;
169
8296
  ConditionVariable platform_workers_ready;
170
171
8296
  Mutex::ScopedLock lock(platform_workers_mutex);
172
4148
  int pending_platform_workers = thread_pool_size;
173
174
8296
  delayed_task_scheduler_ = std::make_unique<DelayedTaskScheduler>(
175
12444
      &pending_worker_tasks_);
176
4148
  threads_.push_back(delayed_task_scheduler_->Start());
177
178
20746
  for (int i = 0; i < thread_pool_size; i++) {
179
    PlatformWorkerData* worker_data = new PlatformWorkerData{
180
16598
      &pending_worker_tasks_, &platform_workers_mutex,
181
      &platform_workers_ready, &pending_platform_workers, i
182
33196
    };
183
33196
    std::unique_ptr<uv_thread_t> t { new uv_thread_t() };
184
16598
    if (uv_thread_create(t.get(), PlatformWorkerThread,
185
                         worker_data) != 0) {
186
      break;
187
    }
188
16598
    threads_.push_back(std::move(t));
189
  }
190
191
  // Wait for platform workers to initialize before continuing with the
192
  // bootstrap.
193
32870
  while (pending_platform_workers > 0) {
194
14361
    platform_workers_ready.Wait(lock);
195
  }
196
4148
}
197
198
117013
void WorkerThreadsTaskRunner::PostTask(std::unique_ptr<Task> task) {
199
117013
  pending_worker_tasks_.Push(std::move(task));
200
117015
}
201
202
68
void WorkerThreadsTaskRunner::PostDelayedTask(std::unique_ptr<Task> task,
203
                                              double delay_in_seconds) {
204
68
  delayed_task_scheduler_->PostDelayedTask(std::move(task), delay_in_seconds);
205
68
}
206
207
9682
void WorkerThreadsTaskRunner::BlockingDrain() {
208
9682
  pending_worker_tasks_.BlockingDrain();
209
9682
}
210
211
4143
void WorkerThreadsTaskRunner::Shutdown() {
212
4143
  pending_worker_tasks_.Stop();
213
4143
  delayed_task_scheduler_->Stop();
214
24864
  for (size_t i = 0; i < threads_.size(); i++) {
215
20721
    CHECK_EQ(0, uv_thread_join(threads_[i].get()));
216
  }
217
4143
}
218
219
4502
int WorkerThreadsTaskRunner::NumberOfWorkerThreads() const {
220
4502
  return threads_.size();
221
}
222
223
4411
PerIsolatePlatformData::PerIsolatePlatformData(
224
4411
    Isolate* isolate, uv_loop_t* loop)
225
4411
  : loop_(loop) {
226
4411
  flush_tasks_ = new uv_async_t();
227
4411
  CHECK_EQ(0, uv_async_init(loop, flush_tasks_, FlushTasks));
228
4411
  flush_tasks_->data = static_cast<void*>(this);
229
4411
  uv_unref(reinterpret_cast<uv_handle_t*>(flush_tasks_));
230
4411
}
231
232
std::shared_ptr<v8::TaskRunner>
233
19721
PerIsolatePlatformData::GetForegroundTaskRunner() {
234
19721
  return shared_from_this();
235
}
236
237
5214
void PerIsolatePlatformData::FlushTasks(uv_async_t* handle) {
238
5214
  auto platform_data = static_cast<PerIsolatePlatformData*>(handle->data);
239
5214
  platform_data->FlushForegroundTasksInternal();
240
5214
}
241
242
void PerIsolatePlatformData::PostIdleTask(std::unique_ptr<v8::IdleTask> task) {
243
  UNREACHABLE();
244
}
245
246
6461
void PerIsolatePlatformData::PostTask(std::unique_ptr<Task> task) {
247
6461
  CHECK_NOT_NULL(flush_tasks_);
248
6461
  foreground_tasks_.Push(std::move(task));
249
6461
  uv_async_send(flush_tasks_);
250
6461
}
251
252
4408
void PerIsolatePlatformData::PostDelayedTask(
253
    std::unique_ptr<Task> task, double delay_in_seconds) {
254
4408
  CHECK_NOT_NULL(flush_tasks_);
255
8816
  std::unique_ptr<DelayedTask> delayed(new DelayedTask());
256
4408
  delayed->task = std::move(task);
257
4408
  delayed->platform_data = shared_from_this();
258
4408
  delayed->timeout = delay_in_seconds;
259
4408
  foreground_delayed_tasks_.Push(std::move(delayed));
260
4408
  uv_async_send(flush_tasks_);
261
4408
}
262
263
181
void PerIsolatePlatformData::PostNonNestableTask(std::unique_ptr<Task> task) {
264
181
  PostTask(std::move(task));
265
181
}
266
267
70
void PerIsolatePlatformData::PostNonNestableDelayedTask(
268
    std::unique_ptr<Task> task,
269
    double delay_in_seconds) {
270
70
  PostDelayedTask(std::move(task), delay_in_seconds);
271
70
}
272
273
540
PerIsolatePlatformData::~PerIsolatePlatformData() {
274
270
  CHECK(!flush_tasks_);
275
270
}
276
277
229
void PerIsolatePlatformData::AddShutdownCallback(void (*callback)(void*),
278
                                                 void* data) {
279
229
  shutdown_callbacks_.emplace_back(ShutdownCallback { callback, data });
280
229
}
281
282
4006
void PerIsolatePlatformData::Shutdown() {
283
4006
  if (flush_tasks_ == nullptr)
284
    return;
285
286
  // While there should be no V8 tasks in the queues at this point, it is
287
  // possible that Node.js-internal tasks from e.g. the inspector are still
288
  // lying around. We clear these queues and ignore the return value,
289
  // effectively deleting the tasks instead of running them.
290
4006
  foreground_delayed_tasks_.PopAll();
291
4006
  foreground_tasks_.PopAll();
292
4006
  scheduled_delayed_tasks_.clear();
293
294
  // Both destroying the scheduled_delayed_tasks_ lists and closing
295
  // flush_tasks_ handle add tasks to the event loop. We keep a count of all
296
  // non-closed handles, and when that reaches zero, we inform any shutdown
297
  // callbacks that the platform is done as far as this Isolate is concerned.
298
4006
  self_reference_ = shared_from_this();
299
8012
  uv_close(reinterpret_cast<uv_handle_t*>(flush_tasks_),
300
4546
           [](uv_handle_t* handle) {
301
    std::unique_ptr<uv_async_t> flush_tasks {
302
540
        reinterpret_cast<uv_async_t*>(handle) };
303
    PerIsolatePlatformData* platform_data =
304
270
        static_cast<PerIsolatePlatformData*>(flush_tasks->data);
305
270
    platform_data->DecreaseHandleCount();
306
270
    platform_data->self_reference_.reset();
307
8552
  });
308
4006
  flush_tasks_ = nullptr;
309
}
310
311
584
void PerIsolatePlatformData::DecreaseHandleCount() {
312
584
  CHECK_GE(uv_handle_count_, 1);
313
584
  if (--uv_handle_count_ == 0) {
314
499
    for (const auto& callback : shutdown_callbacks_)
315
229
      callback.cb(callback.data);
316
  }
317
584
}
318
319
4148
NodePlatform::NodePlatform(int thread_pool_size,
320
4148
                           TracingController* tracing_controller) {
321
4148
  if (tracing_controller) {
322
4148
    tracing_controller_ = tracing_controller;
323
  } else {
324
    tracing_controller_ = new TracingController();
325
  }
326
  worker_thread_task_runner_ =
327
4148
      std::make_shared<WorkerThreadsTaskRunner>(thread_pool_size);
328
4148
}
329
330
4410
void NodePlatform::RegisterIsolate(Isolate* isolate, uv_loop_t* loop) {
331
8820
  Mutex::ScopedLock lock(per_isolate_mutex_);
332
8820
  auto delegate = std::make_shared<PerIsolatePlatformData>(isolate, loop);
333
4410
  IsolatePlatformDelegate* ptr = delegate.get();
334
  auto insertion = per_isolate_.emplace(
335
    isolate,
336
4410
    std::make_pair(ptr, std::move(delegate)));
337
4410
  CHECK(insertion.second);
338
4410
}
339
340
1
void NodePlatform::RegisterIsolate(Isolate* isolate,
341
                                   IsolatePlatformDelegate* delegate) {
342
2
  Mutex::ScopedLock lock(per_isolate_mutex_);
343
  auto insertion = per_isolate_.emplace(
344
    isolate,
345
1
    std::make_pair(delegate, std::shared_ptr<PerIsolatePlatformData>{}));
346
1
  CHECK(insertion.second);
347
1
}
348
349
4006
void NodePlatform::UnregisterIsolate(Isolate* isolate) {
350
8012
  Mutex::ScopedLock lock(per_isolate_mutex_);
351
4006
  auto existing_it = per_isolate_.find(isolate);
352
4006
  CHECK_NE(existing_it, per_isolate_.end());
353
4006
  auto& existing = existing_it->second;
354
4006
  if (existing.second) {
355
4005
    existing.second->Shutdown();
356
  }
357
4006
  per_isolate_.erase(existing_it);
358
4006
}
359
360
229
void NodePlatform::AddIsolateFinishedCallback(Isolate* isolate,
361
                                              void (*cb)(void*), void* data) {
362
458
  Mutex::ScopedLock lock(per_isolate_mutex_);
363
229
  auto it = per_isolate_.find(isolate);
364
229
  if (it == per_isolate_.end()) {
365
    cb(data);
366
    return;
367
  }
368
229
  CHECK(it->second.second);
369
229
  it->second.second->AddShutdownCallback(cb, data);
370
}
371
372
4143
void NodePlatform::Shutdown() {
373
4143
  worker_thread_task_runner_->Shutdown();
374
375
  {
376
8286
    Mutex::ScopedLock lock(per_isolate_mutex_);
377
4143
    per_isolate_.clear();
378
  }
379
4143
}
380
381
4502
int NodePlatform::NumberOfWorkerThreads() {
382
4502
  return worker_thread_task_runner_->NumberOfWorkerThreads();
383
}
384
385
6220
void PerIsolatePlatformData::RunForegroundTask(std::unique_ptr<Task> task) {
386
6220
  Isolate* isolate = Isolate::GetCurrent();
387
6220
  DebugSealHandleScope scope(isolate);
388
6220
  Environment* env = Environment::GetCurrent(isolate);
389
6220
  if (env != nullptr) {
390
12435
    v8::HandleScope scope(isolate);
391
    InternalCallbackScope cb_scope(env, Object::New(isolate), { 0, 0 },
392
12436
                                   InternalCallbackScope::kNoFlags);
393
6217
    task->Run();
394
  } else {
395
2
    task->Run();
396
  }
397
6219
}
398
399
84
void PerIsolatePlatformData::DeleteFromScheduledTasks(DelayedTask* task) {
400
  auto it = std::find_if(scheduled_delayed_tasks_.begin(),
401
                         scheduled_delayed_tasks_.end(),
402
262
                         [task](const DelayedTaskPointer& delayed) -> bool {
403
262
          return delayed.get() == task;
404
84
      });
405
84
  CHECK_NE(it, scheduled_delayed_tasks_.end());
406
84
  scheduled_delayed_tasks_.erase(it);
407
84
}
408
409
84
void PerIsolatePlatformData::RunForegroundTask(uv_timer_t* handle) {
410
84
  DelayedTask* delayed = static_cast<DelayedTask*>(handle->data);
411
84
  RunForegroundTask(std::move(delayed->task));
412
84
  delayed->platform_data->DeleteFromScheduledTasks(delayed);
413
84
}
414
415
7931
void NodePlatform::DrainTasks(Isolate* isolate) {
416
15862
  std::shared_ptr<PerIsolatePlatformData> per_isolate = ForNodeIsolate(isolate);
417
418
9682
  do {
419
    // Worker tasks aren't associated with an Isolate.
420
9682
    worker_thread_task_runner_->BlockingDrain();
421
9682
  } while (per_isolate->FlushForegroundTasksInternal());
422
7931
}
423
424
15204
bool PerIsolatePlatformData::FlushForegroundTasksInternal() {
425
15204
  bool did_work = false;
426
427
  while (std::unique_ptr<DelayedTask> delayed =
428
23542
      foreground_delayed_tasks_.Pop()) {
429
4170
    did_work = true;
430
4170
    uint64_t delay_millis = llround(delayed->timeout * 1000);
431
432
4170
    delayed->timer.data = static_cast<void*>(delayed.get());
433
4170
    uv_timer_init(loop_, &delayed->timer);
434
    // Timers may not guarantee queue ordering of events with the same delay if
435
    // the delay is non-zero. This should not be a problem in practice.
436
4170
    uv_timer_start(&delayed->timer, RunForegroundTask, delay_millis, 0);
437
4169
    uv_unref(reinterpret_cast<uv_handle_t*>(&delayed->timer));
438
4170
    uv_handle_count_++;
439
440
8339
    scheduled_delayed_tasks_.emplace_back(delayed.release(),
441
12236
                                          [](DelayedTask* delayed) {
442
8066
      uv_close(reinterpret_cast<uv_handle_t*>(&delayed->timer),
443
4661
               [](uv_handle_t* handle) {
444
        std::unique_ptr<DelayedTask> task {
445
628
            static_cast<DelayedTask*>(handle->data) };
446
314
        task->platform_data->DecreaseHandleCount();
447
8694
      });
448
16406
    });
449
4169
  }
450
  // Move all foreground tasks into a separate queue and flush that queue.
451
  // This way tasks that are posted while flushing the queue will be run on the
452
  // next call of FlushForegroundTasksInternal.
453
30406
  std::queue<std::unique_ptr<Task>> tasks = foreground_tasks_.PopAll();
454
27470
  while (!tasks.empty()) {
455
12271
    std::unique_ptr<Task> task = std::move(tasks.front());
456
6136
    tasks.pop();
457
6136
    did_work = true;
458
6136
    RunForegroundTask(std::move(task));
459
  }
460
30406
  return did_work;
461
}
462
463
117013
void NodePlatform::CallOnWorkerThread(std::unique_ptr<Task> task) {
464
117013
  worker_thread_task_runner_->PostTask(std::move(task));
465
117015
}
466
467
68
void NodePlatform::CallDelayedOnWorkerThread(std::unique_ptr<Task> task,
468
                                             double delay_in_seconds) {
469
136
  worker_thread_task_runner_->PostDelayedTask(std::move(task),
470
68
                                              delay_in_seconds);
471
68
}
472
473
474
50621
IsolatePlatformDelegate* NodePlatform::ForIsolate(Isolate* isolate) {
475
101242
  Mutex::ScopedLock lock(per_isolate_mutex_);
476
101242
  auto data = per_isolate_[isolate];
477
50621
  CHECK_NOT_NULL(data.first);
478
101242
  return data.first;
479
}
480
481
std::shared_ptr<PerIsolatePlatformData>
482
8239
NodePlatform::ForNodeIsolate(Isolate* isolate) {
483
16479
  Mutex::ScopedLock lock(per_isolate_mutex_);
484
16480
  auto data = per_isolate_[isolate];
485
8240
  CHECK(data.second);
486
16480
  return data.second;
487
}
488
489
308
bool NodePlatform::FlushForegroundTasks(Isolate* isolate) {
490
308
  return ForNodeIsolate(isolate)->FlushForegroundTasksInternal();
491
}
492
493
30900
bool NodePlatform::IdleTasksEnabled(Isolate* isolate) {
494
30900
  return ForIsolate(isolate)->IdleTasksEnabled();
495
}
496
497
std::shared_ptr<v8::TaskRunner>
498
19721
NodePlatform::GetForegroundTaskRunner(Isolate* isolate) {
499
19721
  return ForIsolate(isolate)->GetForegroundTaskRunner();
500
}
501
502
1097958
double NodePlatform::MonotonicallyIncreasingTime() {
503
  // Convert nanos to seconds.
504
1097958
  return uv_hrtime() / 1e9;
505
}
506
507
24217408
double NodePlatform::CurrentClockTimeMillis() {
508
24217408
  return SystemClockTimeMillis();
509
}
510
511
286487
TracingController* NodePlatform::GetTracingController() {
512
286487
  CHECK_NOT_NULL(tracing_controller_);
513
286487
  return tracing_controller_;
514
}
515
516
4148
Platform::StackTracePrinter NodePlatform::GetStackTracePrinter() {
517
4148
  return []() {
518
    fprintf(stderr, "\n");
519
    DumpBacktrace(stderr);
520
    fflush(stderr);
521
8296
  };
522
}
523
524
template <class T>
525
17118
TaskQueue<T>::TaskQueue()
526
    : lock_(), tasks_available_(), tasks_drained_(),
527
17118
      outstanding_tasks_(0), stopped_(false), task_queue_() { }
528
529
template <class T>
530
132094
void TaskQueue<T>::Push(std::unique_ptr<T> task) {
531
264190
  Mutex::ScopedLock scoped_lock(lock_);
532
132096
  outstanding_tasks_++;
533
132096
  task_queue_.push(std::move(task));
534
132096
  tasks_available_.Signal(scoped_lock);
535
132096
}
536
537
template <class T>
538
27792
std::unique_ptr<T> TaskQueue<T>::Pop() {
539
55585
  Mutex::ScopedLock scoped_lock(lock_);
540

27792
  if (task_queue_.empty()) {
541
19412
    return std::unique_ptr<T>(nullptr);
542
  }
543
16761
  std::unique_ptr<T> result = std::move(task_queue_.front());
544
8380
  task_queue_.pop();
545
8381
  return result;
546
}
547
548
template <class T>
549
133553
std::unique_ptr<T> TaskQueue<T>::BlockingPop() {
550
267146
  Mutex::ScopedLock scoped_lock(lock_);
551

377093
  while (task_queue_.empty() && !stopped_) {
552
121760
    tasks_available_.Wait(scoped_lock);
553
  }
554
133593
  if (stopped_) {
555
16578
    return std::unique_ptr<T>(nullptr);
556
  }
557
234030
  std::unique_ptr<T> result = std::move(task_queue_.front());
558
117015
  task_queue_.pop();
559
117015
  return result;
560
}
561
562
template <class T>
563
116573
void TaskQueue<T>::NotifyOfCompletion() {
564
233588
  Mutex::ScopedLock scoped_lock(lock_);
565
117015
  if (--outstanding_tasks_ == 0) {
566
69415
    tasks_drained_.Broadcast(scoped_lock);
567
  }
568
116993
}
569
570
template <class T>
571
9682
void TaskQueue<T>::BlockingDrain() {
572
19364
  Mutex::ScopedLock scoped_lock(lock_);
573
11016
  while (outstanding_tasks_ > 0) {
574
667
    tasks_drained_.Wait(scoped_lock);
575
  }
576
9682
}
577
578
template <class T>
579
4143
void TaskQueue<T>::Stop() {
580
8286
  Mutex::ScopedLock scoped_lock(lock_);
581
4143
  stopped_ = true;
582
4143
  tasks_available_.Broadcast(scoped_lock);
583
4143
}
584
585
template <class T>
586
23215
std::queue<std::unique_ptr<T>> TaskQueue<T>::PopAll() {
587
46425
  Mutex::ScopedLock scoped_lock(lock_);
588
23216
  std::queue<std::unique_ptr<T>> result;
589
23215
  result.swap(task_queue_);
590
46426
  return result;
591
}
592
593
void MultiIsolatePlatform::CancelPendingDelayedTasks(Isolate* isolate) {}
594
595
}  // namespace node