Home | History | Annotate | Download | only in libplatform
      1 // Copyright 2013 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/libplatform/default-platform.h"
      6 
      7 #include <algorithm>
      8 #include <queue>
      9 
     10 #include "src/base/logging.h"
     11 #include "src/base/platform/platform.h"
     12 #include "src/base/platform/time.h"
     13 #include "src/base/sys-info.h"
     14 #include "src/libplatform/worker-thread.h"
     15 
     16 namespace v8 {
     17 namespace platform {
     18 
     19 
     20 v8::Platform* CreateDefaultPlatform(int thread_pool_size) {
     21   DefaultPlatform* platform = new DefaultPlatform();
     22   platform->SetThreadPoolSize(thread_pool_size);
     23   platform->EnsureInitialized();
     24   return platform;
     25 }
     26 
     27 
     28 bool PumpMessageLoop(v8::Platform* platform, v8::Isolate* isolate) {
     29   return reinterpret_cast<DefaultPlatform*>(platform)->PumpMessageLoop(isolate);
     30 }
     31 
     32 const int DefaultPlatform::kMaxThreadPoolSize = 8;
     33 
     34 DefaultPlatform::DefaultPlatform()
     35     : initialized_(false), thread_pool_size_(0) {}
     36 
     37 
     38 DefaultPlatform::~DefaultPlatform() {
     39   base::LockGuard<base::Mutex> guard(&lock_);
     40   queue_.Terminate();
     41   if (initialized_) {
     42     for (auto i = thread_pool_.begin(); i != thread_pool_.end(); ++i) {
     43       delete *i;
     44     }
     45   }
     46   for (auto i = main_thread_queue_.begin(); i != main_thread_queue_.end();
     47        ++i) {
     48     while (!i->second.empty()) {
     49       delete i->second.front();
     50       i->second.pop();
     51     }
     52   }
     53   for (auto i = main_thread_delayed_queue_.begin();
     54        i != main_thread_delayed_queue_.end(); ++i) {
     55     while (!i->second.empty()) {
     56       delete i->second.top().second;
     57       i->second.pop();
     58     }
     59   }
     60 }
     61 
     62 
     63 void DefaultPlatform::SetThreadPoolSize(int thread_pool_size) {
     64   base::LockGuard<base::Mutex> guard(&lock_);
     65   DCHECK(thread_pool_size >= 0);
     66   if (thread_pool_size < 1) {
     67     thread_pool_size = base::SysInfo::NumberOfProcessors() - 1;
     68   }
     69   thread_pool_size_ =
     70       std::max(std::min(thread_pool_size, kMaxThreadPoolSize), 1);
     71 }
     72 
     73 
     74 void DefaultPlatform::EnsureInitialized() {
     75   base::LockGuard<base::Mutex> guard(&lock_);
     76   if (initialized_) return;
     77   initialized_ = true;
     78 
     79   for (int i = 0; i < thread_pool_size_; ++i)
     80     thread_pool_.push_back(new WorkerThread(&queue_));
     81 }
     82 
     83 
     84 Task* DefaultPlatform::PopTaskInMainThreadQueue(v8::Isolate* isolate) {
     85   auto it = main_thread_queue_.find(isolate);
     86   if (it == main_thread_queue_.end() || it->second.empty()) {
     87     return NULL;
     88   }
     89   Task* task = it->second.front();
     90   it->second.pop();
     91   return task;
     92 }
     93 
     94 
     95 Task* DefaultPlatform::PopTaskInMainThreadDelayedQueue(v8::Isolate* isolate) {
     96   auto it = main_thread_delayed_queue_.find(isolate);
     97   if (it == main_thread_delayed_queue_.end() || it->second.empty()) {
     98     return NULL;
     99   }
    100   double now = MonotonicallyIncreasingTime();
    101   std::pair<double, Task*> deadline_and_task = it->second.top();
    102   if (deadline_and_task.first > now) {
    103     return NULL;
    104   }
    105   it->second.pop();
    106   return deadline_and_task.second;
    107 }
    108 
    109 
    110 bool DefaultPlatform::PumpMessageLoop(v8::Isolate* isolate) {
    111   Task* task = NULL;
    112   {
    113     base::LockGuard<base::Mutex> guard(&lock_);
    114 
    115     // Move delayed tasks that hit their deadline to the main queue.
    116     task = PopTaskInMainThreadDelayedQueue(isolate);
    117     while (task != NULL) {
    118       main_thread_queue_[isolate].push(task);
    119       task = PopTaskInMainThreadDelayedQueue(isolate);
    120     }
    121 
    122     task = PopTaskInMainThreadQueue(isolate);
    123 
    124     if (task == NULL) {
    125       return false;
    126     }
    127   }
    128   task->Run();
    129   delete task;
    130   return true;
    131 }
    132 
    133 
    134 void DefaultPlatform::CallOnBackgroundThread(Task *task,
    135                                              ExpectedRuntime expected_runtime) {
    136   EnsureInitialized();
    137   queue_.Append(task);
    138 }
    139 
    140 
    141 void DefaultPlatform::CallOnForegroundThread(v8::Isolate* isolate, Task* task) {
    142   base::LockGuard<base::Mutex> guard(&lock_);
    143   main_thread_queue_[isolate].push(task);
    144 }
    145 
    146 
    147 void DefaultPlatform::CallDelayedOnForegroundThread(Isolate* isolate,
    148                                                     Task* task,
    149                                                     double delay_in_seconds) {
    150   base::LockGuard<base::Mutex> guard(&lock_);
    151   double deadline = MonotonicallyIncreasingTime() + delay_in_seconds;
    152   main_thread_delayed_queue_[isolate].push(std::make_pair(deadline, task));
    153 }
    154 
    155 
    156 void DefaultPlatform::CallIdleOnForegroundThread(Isolate* isolate,
    157                                                  IdleTask* task) {
    158   UNREACHABLE();
    159 }
    160 
    161 
    162 bool DefaultPlatform::IdleTasksEnabled(Isolate* isolate) { return false; }
    163 
    164 
    165 double DefaultPlatform::MonotonicallyIncreasingTime() {
    166   return base::TimeTicks::HighResolutionNow().ToInternalValue() /
    167          static_cast<double>(base::Time::kMicrosecondsPerSecond);
    168 }
    169 
    170 
    171 uint64_t DefaultPlatform::AddTraceEvent(
    172     char phase, const uint8_t* category_enabled_flag, const char* name,
    173     const char* scope, uint64_t id, uint64_t bind_id, int num_args,
    174     const char** arg_names, const uint8_t* arg_types,
    175     const uint64_t* arg_values, unsigned int flags) {
    176   return 0;
    177 }
    178 
    179 
    180 void DefaultPlatform::UpdateTraceEventDuration(
    181     const uint8_t* category_enabled_flag, const char* name, uint64_t handle) {}
    182 
    183 
    184 const uint8_t* DefaultPlatform::GetCategoryGroupEnabled(const char* name) {
    185   static uint8_t no = 0;
    186   return &no;
    187 }
    188 
    189 
    190 const char* DefaultPlatform::GetCategoryGroupName(
    191     const uint8_t* category_enabled_flag) {
    192   static const char dummy[] = "dummy";
    193   return dummy;
    194 }
    195 
    196 
    197 size_t DefaultPlatform::NumberOfAvailableBackgroundThreads() {
    198   return static_cast<size_t>(thread_pool_size_);
    199 }
    200 
    201 }  // namespace platform
    202 }  // namespace v8
    203