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 "include/libplatform/libplatform.h"
     11 #include "src/base/logging.h"
     12 #include "src/base/platform/platform.h"
     13 #include "src/base/platform/time.h"
     14 #include "src/base/sys-info.h"
     15 #include "src/libplatform/worker-thread.h"
     16 
     17 namespace v8 {
     18 namespace platform {
     19 
     20 
     21 v8::Platform* CreateDefaultPlatform(int thread_pool_size) {
     22   DefaultPlatform* platform = new DefaultPlatform();
     23   platform->SetThreadPoolSize(thread_pool_size);
     24   platform->EnsureInitialized();
     25   return platform;
     26 }
     27 
     28 
     29 bool PumpMessageLoop(v8::Platform* platform, v8::Isolate* isolate) {
     30   return reinterpret_cast<DefaultPlatform*>(platform)->PumpMessageLoop(isolate);
     31 }
     32 
     33 void SetTracingController(
     34     v8::Platform* platform,
     35     v8::platform::tracing::TracingController* tracing_controller) {
     36   return reinterpret_cast<DefaultPlatform*>(platform)->SetTracingController(
     37       tracing_controller);
     38 }
     39 
     40 const int DefaultPlatform::kMaxThreadPoolSize = 8;
     41 
     42 DefaultPlatform::DefaultPlatform()
     43     : initialized_(false), thread_pool_size_(0) {}
     44 
     45 DefaultPlatform::~DefaultPlatform() {
     46   if (tracing_controller_) {
     47     tracing_controller_->StopTracing();
     48     tracing_controller_.reset();
     49   }
     50 
     51   base::LockGuard<base::Mutex> guard(&lock_);
     52   queue_.Terminate();
     53   if (initialized_) {
     54     for (auto i = thread_pool_.begin(); i != thread_pool_.end(); ++i) {
     55       delete *i;
     56     }
     57   }
     58   for (auto i = main_thread_queue_.begin(); i != main_thread_queue_.end();
     59        ++i) {
     60     while (!i->second.empty()) {
     61       delete i->second.front();
     62       i->second.pop();
     63     }
     64   }
     65   for (auto i = main_thread_delayed_queue_.begin();
     66        i != main_thread_delayed_queue_.end(); ++i) {
     67     while (!i->second.empty()) {
     68       delete i->second.top().second;
     69       i->second.pop();
     70     }
     71   }
     72 }
     73 
     74 
     75 void DefaultPlatform::SetThreadPoolSize(int thread_pool_size) {
     76   base::LockGuard<base::Mutex> guard(&lock_);
     77   DCHECK(thread_pool_size >= 0);
     78   if (thread_pool_size < 1) {
     79     thread_pool_size = base::SysInfo::NumberOfProcessors() - 1;
     80   }
     81   thread_pool_size_ =
     82       std::max(std::min(thread_pool_size, kMaxThreadPoolSize), 1);
     83 }
     84 
     85 
     86 void DefaultPlatform::EnsureInitialized() {
     87   base::LockGuard<base::Mutex> guard(&lock_);
     88   if (initialized_) return;
     89   initialized_ = true;
     90 
     91   for (int i = 0; i < thread_pool_size_; ++i)
     92     thread_pool_.push_back(new WorkerThread(&queue_));
     93 }
     94 
     95 
     96 Task* DefaultPlatform::PopTaskInMainThreadQueue(v8::Isolate* isolate) {
     97   auto it = main_thread_queue_.find(isolate);
     98   if (it == main_thread_queue_.end() || it->second.empty()) {
     99     return NULL;
    100   }
    101   Task* task = it->second.front();
    102   it->second.pop();
    103   return task;
    104 }
    105 
    106 
    107 Task* DefaultPlatform::PopTaskInMainThreadDelayedQueue(v8::Isolate* isolate) {
    108   auto it = main_thread_delayed_queue_.find(isolate);
    109   if (it == main_thread_delayed_queue_.end() || it->second.empty()) {
    110     return NULL;
    111   }
    112   double now = MonotonicallyIncreasingTime();
    113   std::pair<double, Task*> deadline_and_task = it->second.top();
    114   if (deadline_and_task.first > now) {
    115     return NULL;
    116   }
    117   it->second.pop();
    118   return deadline_and_task.second;
    119 }
    120 
    121 
    122 bool DefaultPlatform::PumpMessageLoop(v8::Isolate* isolate) {
    123   Task* task = NULL;
    124   {
    125     base::LockGuard<base::Mutex> guard(&lock_);
    126 
    127     // Move delayed tasks that hit their deadline to the main queue.
    128     task = PopTaskInMainThreadDelayedQueue(isolate);
    129     while (task != NULL) {
    130       main_thread_queue_[isolate].push(task);
    131       task = PopTaskInMainThreadDelayedQueue(isolate);
    132     }
    133 
    134     task = PopTaskInMainThreadQueue(isolate);
    135 
    136     if (task == NULL) {
    137       return false;
    138     }
    139   }
    140   task->Run();
    141   delete task;
    142   return true;
    143 }
    144 
    145 
    146 void DefaultPlatform::CallOnBackgroundThread(Task *task,
    147                                              ExpectedRuntime expected_runtime) {
    148   EnsureInitialized();
    149   queue_.Append(task);
    150 }
    151 
    152 
    153 void DefaultPlatform::CallOnForegroundThread(v8::Isolate* isolate, Task* task) {
    154   base::LockGuard<base::Mutex> guard(&lock_);
    155   main_thread_queue_[isolate].push(task);
    156 }
    157 
    158 
    159 void DefaultPlatform::CallDelayedOnForegroundThread(Isolate* isolate,
    160                                                     Task* task,
    161                                                     double delay_in_seconds) {
    162   base::LockGuard<base::Mutex> guard(&lock_);
    163   double deadline = MonotonicallyIncreasingTime() + delay_in_seconds;
    164   main_thread_delayed_queue_[isolate].push(std::make_pair(deadline, task));
    165 }
    166 
    167 
    168 void DefaultPlatform::CallIdleOnForegroundThread(Isolate* isolate,
    169                                                  IdleTask* task) {
    170   UNREACHABLE();
    171 }
    172 
    173 
    174 bool DefaultPlatform::IdleTasksEnabled(Isolate* isolate) { return false; }
    175 
    176 
    177 double DefaultPlatform::MonotonicallyIncreasingTime() {
    178   return base::TimeTicks::HighResolutionNow().ToInternalValue() /
    179          static_cast<double>(base::Time::kMicrosecondsPerSecond);
    180 }
    181 
    182 uint64_t DefaultPlatform::AddTraceEvent(
    183     char phase, const uint8_t* category_enabled_flag, const char* name,
    184     const char* scope, uint64_t id, uint64_t bind_id, int num_args,
    185     const char** arg_names, const uint8_t* arg_types,
    186     const uint64_t* arg_values,
    187     std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables,
    188     unsigned int flags) {
    189   if (tracing_controller_) {
    190     return tracing_controller_->AddTraceEvent(
    191         phase, category_enabled_flag, name, scope, id, bind_id, num_args,
    192         arg_names, arg_types, arg_values, arg_convertables, flags);
    193   }
    194 
    195   return 0;
    196 }
    197 
    198 void DefaultPlatform::UpdateTraceEventDuration(
    199     const uint8_t* category_enabled_flag, const char* name, uint64_t handle) {
    200   if (tracing_controller_) {
    201     tracing_controller_->UpdateTraceEventDuration(category_enabled_flag, name,
    202                                                   handle);
    203   }
    204 }
    205 
    206 const uint8_t* DefaultPlatform::GetCategoryGroupEnabled(const char* name) {
    207   if (tracing_controller_) {
    208     return tracing_controller_->GetCategoryGroupEnabled(name);
    209   }
    210   static uint8_t no = 0;
    211   return &no;
    212 }
    213 
    214 
    215 const char* DefaultPlatform::GetCategoryGroupName(
    216     const uint8_t* category_enabled_flag) {
    217   static const char dummy[] = "dummy";
    218   return dummy;
    219 }
    220 
    221 void DefaultPlatform::SetTracingController(
    222     tracing::TracingController* tracing_controller) {
    223   tracing_controller_.reset(tracing_controller);
    224 }
    225 
    226 size_t DefaultPlatform::NumberOfAvailableBackgroundThreads() {
    227   return static_cast<size_t>(thread_pool_size_);
    228 }
    229 
    230 void DefaultPlatform::AddTraceStateObserver(TraceStateObserver* observer) {
    231   if (!tracing_controller_) return;
    232   tracing_controller_->AddTraceStateObserver(observer);
    233 }
    234 
    235 void DefaultPlatform::RemoveTraceStateObserver(TraceStateObserver* observer) {
    236   if (!tracing_controller_) return;
    237   tracing_controller_->RemoveTraceStateObserver(observer);
    238 }
    239 
    240 }  // namespace platform
    241 }  // namespace v8
    242