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