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