current commit
240422.4 · deps: update V8 to 12.4.254.14
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/libplatform/default-worker-threads-task-runner.h"

#include "src/base/platform/time.h"
#include "src/libplatform/delayed-task-queue.h"

namespace v8 {
namespace platform {

DefaultWorkerThreadsTaskRunner::DefaultWorkerThreadsTaskRunner(
    uint32_t thread_pool_size, TimeFunction time_function,
    base::Thread::Priority priority)
    : queue_(time_function), time_function_(time_function) {
  for (uint32_t i = 0; i < thread_pool_size; ++i) {
    thread_pool_.push_back(std::make_unique<WorkerThread>(this, priority));
  }
}

DefaultWorkerThreadsTaskRunner::~DefaultWorkerThreadsTaskRunner() = default;

double DefaultWorkerThreadsTaskRunner::MonotonicallyIncreasingTime() {
  return time_function_();
}

void DefaultWorkerThreadsTaskRunner::Terminate() {
  {
    base::MutexGuard guard(&lock_);
    terminated_ = true;
    queue_.Terminate();
    idle_threads_.clear();
  }
  // Clearing the thread pool lets all worker threads join.
  thread_pool_.clear();
}

void DefaultWorkerThreadsTaskRunner::PostTaskImpl(
    std::unique_ptr<Task> task, const SourceLocation& location) {
  base::MutexGuard guard(&lock_);
  if (terminated_) return;
  queue_.Append(std::move(task));

  if (!idle_threads_.empty()) {
    idle_threads_.back()->Notify();
    idle_threads_.pop_back();
  }
}

void DefaultWorkerThreadsTaskRunner::PostDelayedTaskImpl(
    std::unique_ptr<Task> task, double delay_in_seconds,
    const SourceLocation& location) {
  base::MutexGuard guard(&lock_);
  if (terminated_) return;
  queue_.AppendDelayed(std::move(task), delay_in_seconds);

  if (!idle_threads_.empty()) {
    idle_threads_.back()->Notify();
    idle_threads_.pop_back();
  }
}

void DefaultWorkerThreadsTaskRunner::PostIdleTaskImpl(
    std::unique_ptr<IdleTask> task, const SourceLocation& location) {
  // There are no idle worker tasks.
  UNREACHABLE();
}

bool DefaultWorkerThreadsTaskRunner::IdleTasksEnabled() {
  // There are no idle worker tasks.
  return false;
}

DefaultWorkerThreadsTaskRunner::WorkerThread::WorkerThread(
    DefaultWorkerThreadsTaskRunner* runner, base::Thread::Priority priority)
    : Thread(
          Options("V8 DefaultWorkerThreadsTaskRunner WorkerThread", priority)),
      runner_(runner) {
  CHECK(Start());
}

DefaultWorkerThreadsTaskRunner::WorkerThread::~WorkerThread() {
  condition_var_.NotifyAll();
  Join();
}

void DefaultWorkerThreadsTaskRunner::WorkerThread::Run() {
  base::MutexGuard guard(&runner_->lock_);
  while (true) {
    DelayedTaskQueue::MaybeNextTask next_task = runner_->queue_.TryGetNext();
    switch (next_task.state) {
      case DelayedTaskQueue::MaybeNextTask::kTask:
        runner_->lock_.Unlock();
        next_task.task->Run();
        runner_->lock_.Lock();
        continue;
      case DelayedTaskQueue::MaybeNextTask::kTerminated:
        return;
      case DelayedTaskQueue::MaybeNextTask::kWaitIndefinite:
        runner_->idle_threads_.push_back(this);
        condition_var_.Wait(&runner_->lock_);
        continue;
      case DelayedTaskQueue::MaybeNextTask::kWaitDelayed:
        // WaitFor unfortunately doesn't care about our fake time and will wait
        // the 'real' amount of time, based on whatever clock the system call
        // uses.
        runner_->idle_threads_.push_back(this);
        bool notified =
            condition_var_.WaitFor(&runner_->lock_, next_task.wait_time);
        USE(notified);
        continue;
    }
  }
}

void DefaultWorkerThreadsTaskRunner::WorkerThread::Notify() {
  condition_var_.NotifyAll();
}

}  // namespace platform
}  // namespace v8