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