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 33 const int DefaultPlatform::kMaxThreadPoolSize = 4; 34 35 36 DefaultPlatform::DefaultPlatform() 37 : initialized_(false), thread_pool_size_(0) {} 38 39 40 DefaultPlatform::~DefaultPlatform() { 41 base::LockGuard<base::Mutex> guard(&lock_); 42 queue_.Terminate(); 43 if (initialized_) { 44 for (auto i = thread_pool_.begin(); i != thread_pool_.end(); ++i) { 45 delete *i; 46 } 47 } 48 for (auto i = main_thread_queue_.begin(); i != main_thread_queue_.end(); 49 ++i) { 50 while (!i->second.empty()) { 51 delete i->second.front(); 52 i->second.pop(); 53 } 54 } 55 for (auto i = main_thread_delayed_queue_.begin(); 56 i != main_thread_delayed_queue_.end(); ++i) { 57 while (!i->second.empty()) { 58 delete i->second.top().second; 59 i->second.pop(); 60 } 61 } 62 } 63 64 65 void DefaultPlatform::SetThreadPoolSize(int thread_pool_size) { 66 base::LockGuard<base::Mutex> guard(&lock_); 67 DCHECK(thread_pool_size >= 0); 68 if (thread_pool_size < 1) { 69 thread_pool_size = base::SysInfo::NumberOfProcessors(); 70 } 71 thread_pool_size_ = 72 std::max(std::min(thread_pool_size, kMaxThreadPoolSize), 1); 73 } 74 75 76 void DefaultPlatform::EnsureInitialized() { 77 base::LockGuard<base::Mutex> guard(&lock_); 78 if (initialized_) return; 79 initialized_ = true; 80 81 for (int i = 0; i < thread_pool_size_; ++i) 82 thread_pool_.push_back(new WorkerThread(&queue_)); 83 } 84 85 86 Task* DefaultPlatform::PopTaskInMainThreadQueue(v8::Isolate* isolate) { 87 auto it = main_thread_queue_.find(isolate); 88 if (it == main_thread_queue_.end() || it->second.empty()) { 89 return NULL; 90 } 91 Task* task = it->second.front(); 92 it->second.pop(); 93 return task; 94 } 95 96 97 Task* DefaultPlatform::PopTaskInMainThreadDelayedQueue(v8::Isolate* isolate) { 98 auto it = main_thread_delayed_queue_.find(isolate); 99 if (it == main_thread_delayed_queue_.end() || it->second.empty()) { 100 return NULL; 101 } 102 double now = MonotonicallyIncreasingTime(); 103 std::pair<double, Task*> deadline_and_task = it->second.top(); 104 if (deadline_and_task.first > now) { 105 return NULL; 106 } 107 it->second.pop(); 108 return deadline_and_task.second; 109 } 110 111 112 bool DefaultPlatform::PumpMessageLoop(v8::Isolate* isolate) { 113 Task* task = NULL; 114 { 115 base::LockGuard<base::Mutex> guard(&lock_); 116 117 // Move delayed tasks that hit their deadline to the main queue. 118 task = PopTaskInMainThreadDelayedQueue(isolate); 119 while (task != NULL) { 120 main_thread_queue_[isolate].push(task); 121 task = PopTaskInMainThreadDelayedQueue(isolate); 122 } 123 124 task = PopTaskInMainThreadQueue(isolate); 125 126 if (task == NULL) { 127 return false; 128 } 129 } 130 task->Run(); 131 delete task; 132 return true; 133 } 134 135 136 void DefaultPlatform::CallOnBackgroundThread(Task *task, 137 ExpectedRuntime expected_runtime) { 138 EnsureInitialized(); 139 queue_.Append(task); 140 } 141 142 143 void DefaultPlatform::CallOnForegroundThread(v8::Isolate* isolate, Task* task) { 144 base::LockGuard<base::Mutex> guard(&lock_); 145 main_thread_queue_[isolate].push(task); 146 } 147 148 149 void DefaultPlatform::CallDelayedOnForegroundThread(Isolate* isolate, 150 Task* task, 151 double delay_in_seconds) { 152 base::LockGuard<base::Mutex> guard(&lock_); 153 double deadline = MonotonicallyIncreasingTime() + delay_in_seconds; 154 main_thread_delayed_queue_[isolate].push(std::make_pair(deadline, task)); 155 } 156 157 158 void DefaultPlatform::CallIdleOnForegroundThread(Isolate* isolate, 159 IdleTask* task) { 160 UNREACHABLE(); 161 } 162 163 164 bool DefaultPlatform::IdleTasksEnabled(Isolate* isolate) { return false; } 165 166 167 double DefaultPlatform::MonotonicallyIncreasingTime() { 168 return base::TimeTicks::HighResolutionNow().ToInternalValue() / 169 static_cast<double>(base::Time::kMicrosecondsPerSecond); 170 } 171 172 173 uint64_t DefaultPlatform::AddTraceEvent( 174 char phase, const uint8_t* category_enabled_flag, const char* name, 175 uint64_t id, uint64_t bind_id, int num_args, const char** arg_names, 176 const uint8_t* arg_types, const uint64_t* arg_values, unsigned int flags) { 177 return 0; 178 } 179 180 181 void DefaultPlatform::UpdateTraceEventDuration( 182 const uint8_t* category_enabled_flag, const char* name, uint64_t handle) {} 183 184 185 const uint8_t* DefaultPlatform::GetCategoryGroupEnabled(const char* name) { 186 static uint8_t no = 0; 187 return &no; 188 } 189 190 191 const char* DefaultPlatform::GetCategoryGroupName( 192 const uint8_t* category_enabled_flag) { 193 static const char dummy[] = "dummy"; 194 return dummy; 195 } 196 } // namespace platform 197 } // namespace v8 198