Line data Source code
1 : // Copyright 2018 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 <memory>
6 : #include <unordered_map>
7 :
8 : #include "include/v8-platform.h"
9 : #include "src/base/logging.h"
10 : #include "src/base/macros.h"
11 : #include "src/base/platform/mutex.h"
12 : #include "src/base/platform/platform.h"
13 : #include "src/base/platform/time.h"
14 : #include "src/base/template-utils.h"
15 : #include "src/base/utils/random-number-generator.h"
16 : #include "src/d8-platforms.h"
17 :
18 : namespace v8 {
19 :
20 0 : class PredictablePlatform : public Platform {
21 : public:
22 : explicit PredictablePlatform(std::unique_ptr<Platform> platform)
23 0 : : platform_(std::move(platform)) {
24 : DCHECK_NOT_NULL(platform_);
25 : }
26 :
27 0 : PageAllocator* GetPageAllocator() override {
28 0 : return platform_->GetPageAllocator();
29 : }
30 :
31 0 : void OnCriticalMemoryPressure() override {
32 0 : platform_->OnCriticalMemoryPressure();
33 0 : }
34 :
35 0 : bool OnCriticalMemoryPressure(size_t length) override {
36 0 : return platform_->OnCriticalMemoryPressure(length);
37 : }
38 :
39 0 : std::shared_ptr<TaskRunner> GetForegroundTaskRunner(
40 : v8::Isolate* isolate) override {
41 0 : return platform_->GetForegroundTaskRunner(isolate);
42 : }
43 :
44 0 : int NumberOfWorkerThreads() override { return 0; }
45 :
46 0 : void CallOnWorkerThread(std::unique_ptr<Task> task) override {
47 : // It's not defined when background tasks are being executed, so we can just
48 : // execute them right away.
49 0 : task->Run();
50 0 : }
51 :
52 0 : void CallDelayedOnWorkerThread(std::unique_ptr<Task> task,
53 : double delay_in_seconds) override {
54 : // Never run delayed tasks.
55 0 : }
56 :
57 0 : void CallOnForegroundThread(v8::Isolate* isolate, Task* task) override {
58 : // This is a deprecated function and should not be called anymore.
59 0 : UNREACHABLE();
60 : }
61 :
62 0 : void CallDelayedOnForegroundThread(v8::Isolate* isolate, Task* task,
63 : double delay_in_seconds) override {
64 : // This is a deprecated function and should not be called anymore.
65 0 : UNREACHABLE();
66 : }
67 :
68 0 : void CallIdleOnForegroundThread(Isolate* isolate, IdleTask* task) override {
69 0 : UNREACHABLE();
70 : }
71 :
72 0 : bool IdleTasksEnabled(Isolate* isolate) override { return false; }
73 :
74 0 : double MonotonicallyIncreasingTime() override {
75 0 : return synthetic_time_in_sec_ += 0.00001;
76 : }
77 :
78 0 : double CurrentClockTimeMillis() override {
79 0 : return MonotonicallyIncreasingTime() * base::Time::kMillisecondsPerSecond;
80 : }
81 :
82 0 : v8::TracingController* GetTracingController() override {
83 0 : return platform_->GetTracingController();
84 : }
85 :
86 : Platform* platform() const { return platform_.get(); }
87 :
88 : private:
89 : double synthetic_time_in_sec_ = 0.0;
90 : std::unique_ptr<Platform> platform_;
91 :
92 : DISALLOW_COPY_AND_ASSIGN(PredictablePlatform);
93 : };
94 :
95 0 : std::unique_ptr<Platform> MakePredictablePlatform(
96 : std::unique_ptr<Platform> platform) {
97 0 : return base::make_unique<PredictablePlatform>(std::move(platform));
98 : }
99 :
100 : class DelayedTasksPlatform : public Platform {
101 : public:
102 0 : explicit DelayedTasksPlatform(std::unique_ptr<Platform> platform)
103 0 : : platform_(std::move(platform)) {
104 : DCHECK_NOT_NULL(platform_);
105 0 : }
106 :
107 0 : explicit DelayedTasksPlatform(std::unique_ptr<Platform> platform,
108 : int64_t random_seed)
109 0 : : platform_(std::move(platform)), rng_(random_seed) {
110 : DCHECK_NOT_NULL(platform_);
111 0 : }
112 :
113 0 : ~DelayedTasksPlatform() {
114 : // When the platform shuts down, all task runners must be freed.
115 : DCHECK_EQ(0, delayed_task_runners_.size());
116 0 : }
117 :
118 0 : PageAllocator* GetPageAllocator() override {
119 0 : return platform_->GetPageAllocator();
120 : }
121 :
122 0 : void OnCriticalMemoryPressure() override {
123 0 : platform_->OnCriticalMemoryPressure();
124 0 : }
125 :
126 0 : bool OnCriticalMemoryPressure(size_t length) override {
127 0 : return platform_->OnCriticalMemoryPressure(length);
128 : }
129 :
130 0 : std::shared_ptr<TaskRunner> GetForegroundTaskRunner(
131 : v8::Isolate* isolate) override {
132 : std::shared_ptr<TaskRunner> runner =
133 0 : platform_->GetForegroundTaskRunner(isolate);
134 :
135 0 : base::MutexGuard lock_guard(&mutex_);
136 : // Check if we can re-materialize the weak ptr in our map.
137 : std::weak_ptr<DelayedTaskRunner>& weak_delayed_runner =
138 0 : delayed_task_runners_[runner.get()];
139 : std::shared_ptr<DelayedTaskRunner> delayed_runner =
140 : weak_delayed_runner.lock();
141 :
142 0 : if (!delayed_runner) {
143 : // Create a new {DelayedTaskRunner} and keep a weak reference in our map.
144 0 : delayed_runner.reset(new DelayedTaskRunner(runner, this),
145 0 : DelayedTaskRunnerDeleter{});
146 : weak_delayed_runner = delayed_runner;
147 : }
148 :
149 0 : return std::move(delayed_runner);
150 : }
151 :
152 0 : int NumberOfWorkerThreads() override {
153 0 : return platform_->NumberOfWorkerThreads();
154 : }
155 :
156 0 : void CallOnWorkerThread(std::unique_ptr<Task> task) override {
157 0 : platform_->CallOnWorkerThread(MakeDelayedTask(std::move(task)));
158 0 : }
159 :
160 0 : void CallDelayedOnWorkerThread(std::unique_ptr<Task> task,
161 : double delay_in_seconds) override {
162 0 : platform_->CallDelayedOnWorkerThread(MakeDelayedTask(std::move(task)),
163 0 : delay_in_seconds);
164 0 : }
165 :
166 0 : void CallOnForegroundThread(v8::Isolate* isolate, Task* task) override {
167 : // This is a deprecated function and should not be called anymore.
168 0 : UNREACHABLE();
169 : }
170 :
171 0 : void CallDelayedOnForegroundThread(v8::Isolate* isolate, Task* task,
172 : double delay_in_seconds) override {
173 : // This is a deprecated function and should not be called anymore.
174 0 : UNREACHABLE();
175 : }
176 :
177 0 : void CallIdleOnForegroundThread(Isolate* isolate, IdleTask* task) override {
178 : // This is a deprecated function and should not be called anymore.
179 0 : UNREACHABLE();
180 : }
181 :
182 0 : bool IdleTasksEnabled(Isolate* isolate) override {
183 0 : return platform_->IdleTasksEnabled(isolate);
184 : }
185 :
186 0 : double MonotonicallyIncreasingTime() override {
187 0 : return platform_->MonotonicallyIncreasingTime();
188 : }
189 :
190 0 : double CurrentClockTimeMillis() override {
191 0 : return platform_->CurrentClockTimeMillis();
192 : }
193 :
194 0 : v8::TracingController* GetTracingController() override {
195 0 : return platform_->GetTracingController();
196 : }
197 :
198 : private:
199 : class DelayedTaskRunnerDeleter;
200 0 : class DelayedTaskRunner final : public TaskRunner {
201 : public:
202 : DelayedTaskRunner(std::shared_ptr<TaskRunner> task_runner,
203 : DelayedTasksPlatform* platform)
204 0 : : task_runner_(task_runner), platform_(platform) {}
205 :
206 0 : void PostTask(std::unique_ptr<Task> task) final {
207 0 : task_runner_->PostTask(platform_->MakeDelayedTask(std::move(task)));
208 0 : }
209 :
210 0 : void PostDelayedTask(std::unique_ptr<Task> task,
211 : double delay_in_seconds) final {
212 0 : task_runner_->PostDelayedTask(platform_->MakeDelayedTask(std::move(task)),
213 0 : delay_in_seconds);
214 0 : }
215 :
216 0 : void PostIdleTask(std::unique_ptr<IdleTask> task) final {
217 : task_runner_->PostIdleTask(
218 0 : platform_->MakeDelayedIdleTask(std::move(task)));
219 0 : }
220 :
221 0 : bool IdleTasksEnabled() final { return task_runner_->IdleTasksEnabled(); }
222 :
223 : private:
224 : friend class DelayedTaskRunnerDeleter;
225 : std::shared_ptr<TaskRunner> task_runner_;
226 : DelayedTasksPlatform* platform_;
227 : };
228 :
229 : class DelayedTaskRunnerDeleter {
230 : public:
231 0 : void operator()(DelayedTaskRunner* runner) const {
232 0 : TaskRunner* original_runner = runner->task_runner_.get();
233 0 : base::MutexGuard lock_guard(&runner->platform_->mutex_);
234 0 : auto& delayed_task_runners = runner->platform_->delayed_task_runners_;
235 : DCHECK_EQ(1, delayed_task_runners.count(original_runner));
236 : delayed_task_runners.erase(original_runner);
237 0 : }
238 : };
239 :
240 0 : class DelayedTask : public Task {
241 : public:
242 : DelayedTask(std::unique_ptr<Task> task, int32_t delay_ms)
243 0 : : task_(std::move(task)), delay_ms_(delay_ms) {}
244 0 : void Run() final {
245 0 : base::OS::Sleep(base::TimeDelta::FromMicroseconds(delay_ms_));
246 0 : task_->Run();
247 0 : }
248 :
249 : private:
250 : std::unique_ptr<Task> task_;
251 : int32_t delay_ms_;
252 : };
253 :
254 0 : class DelayedIdleTask : public IdleTask {
255 : public:
256 : DelayedIdleTask(std::unique_ptr<IdleTask> task, int32_t delay_ms)
257 0 : : task_(std::move(task)), delay_ms_(delay_ms) {}
258 0 : void Run(double deadline_in_seconds) final {
259 0 : base::OS::Sleep(base::TimeDelta::FromMicroseconds(delay_ms_));
260 0 : task_->Run(deadline_in_seconds);
261 0 : }
262 :
263 : private:
264 : std::unique_ptr<IdleTask> task_;
265 : int32_t delay_ms_;
266 : };
267 :
268 : std::unique_ptr<Platform> platform_;
269 :
270 : // The Mutex protects the RNG, which is used by foreground and background
271 : // threads, and the {delayed_task_runners_} map might be accessed concurrently
272 : // by the shared_ptr destructor.
273 : base::Mutex mutex_;
274 : base::RandomNumberGenerator rng_;
275 : std::unordered_map<TaskRunner*, std::weak_ptr<DelayedTaskRunner>>
276 : delayed_task_runners_;
277 :
278 0 : int32_t GetRandomDelayInMilliseconds() {
279 0 : base::MutexGuard lock_guard(&mutex_);
280 0 : double delay_fraction = rng_.NextDouble();
281 : // Sleep up to 100ms (100000us). Square {delay_fraction} to shift
282 : // distribution towards shorter sleeps.
283 0 : return 1e5 * (delay_fraction * delay_fraction);
284 : }
285 :
286 0 : std::unique_ptr<Task> MakeDelayedTask(std::unique_ptr<Task> task) {
287 : return base::make_unique<DelayedTask>(std::move(task),
288 0 : GetRandomDelayInMilliseconds());
289 : }
290 :
291 0 : std::unique_ptr<IdleTask> MakeDelayedIdleTask(
292 : std::unique_ptr<IdleTask> task) {
293 : return base::make_unique<DelayedIdleTask>(std::move(task),
294 0 : GetRandomDelayInMilliseconds());
295 : }
296 :
297 : DISALLOW_COPY_AND_ASSIGN(DelayedTasksPlatform);
298 : };
299 :
300 0 : std::unique_ptr<Platform> MakeDelayedTasksPlatform(
301 : std::unique_ptr<Platform> platform, int64_t random_seed) {
302 0 : if (random_seed) {
303 0 : return base::make_unique<DelayedTasksPlatform>(std::move(platform),
304 : random_seed);
305 : }
306 0 : return base::make_unique<DelayedTasksPlatform>(std::move(platform));
307 : }
308 :
309 : } // namespace v8
|