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