/src/node/deps/v8/include/cppgc/platform.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2020 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 | | #ifndef INCLUDE_CPPGC_PLATFORM_H_ |
6 | | #define INCLUDE_CPPGC_PLATFORM_H_ |
7 | | |
8 | | #include <memory> |
9 | | |
10 | | #include "cppgc/source-location.h" |
11 | | #include "v8-platform.h" // NOLINT(build/include_directory) |
12 | | #include "v8config.h" // NOLINT(build/include_directory) |
13 | | |
14 | | namespace cppgc { |
15 | | |
16 | | // TODO(v8:10346): Create separate includes for concepts that are not |
17 | | // V8-specific. |
18 | | using IdleTask = v8::IdleTask; |
19 | | using JobHandle = v8::JobHandle; |
20 | | using JobDelegate = v8::JobDelegate; |
21 | | using JobTask = v8::JobTask; |
22 | | using PageAllocator = v8::PageAllocator; |
23 | | using Task = v8::Task; |
24 | | using TaskPriority = v8::TaskPriority; |
25 | | using TaskRunner = v8::TaskRunner; |
26 | | using TracingController = v8::TracingController; |
27 | | |
28 | | /** |
29 | | * Platform interface used by Heap. Contains allocators and executors. |
30 | | */ |
31 | | class V8_EXPORT Platform { |
32 | | public: |
33 | | virtual ~Platform() = default; |
34 | | |
35 | | /** |
36 | | * \returns the allocator used by cppgc to allocate its heap and various |
37 | | * support structures. Returning nullptr results in using the `PageAllocator` |
38 | | * provided by `cppgc::InitializeProcess()` instead. |
39 | | */ |
40 | | virtual PageAllocator* GetPageAllocator() = 0; |
41 | | |
42 | | /** |
43 | | * Monotonically increasing time in seconds from an arbitrary fixed point in |
44 | | * the past. This function is expected to return at least |
45 | | * millisecond-precision values. For this reason, |
46 | | * it is recommended that the fixed point be no further in the past than |
47 | | * the epoch. |
48 | | **/ |
49 | | virtual double MonotonicallyIncreasingTime() = 0; |
50 | | |
51 | | /** |
52 | | * Foreground task runner that should be used by a Heap. |
53 | | */ |
54 | 0 | virtual std::shared_ptr<TaskRunner> GetForegroundTaskRunner() { |
55 | 0 | return nullptr; |
56 | 0 | } |
57 | | |
58 | | /** |
59 | | * Posts `job_task` to run in parallel. Returns a `JobHandle` associated with |
60 | | * the `Job`, which can be joined or canceled. |
61 | | * This avoids degenerate cases: |
62 | | * - Calling `CallOnWorkerThread()` for each work item, causing significant |
63 | | * overhead. |
64 | | * - Fixed number of `CallOnWorkerThread()` calls that split the work and |
65 | | * might run for a long time. This is problematic when many components post |
66 | | * "num cores" tasks and all expect to use all the cores. In these cases, |
67 | | * the scheduler lacks context to be fair to multiple same-priority requests |
68 | | * and/or ability to request lower priority work to yield when high priority |
69 | | * work comes in. |
70 | | * A canonical implementation of `job_task` looks like: |
71 | | * \code |
72 | | * class MyJobTask : public JobTask { |
73 | | * public: |
74 | | * MyJobTask(...) : worker_queue_(...) {} |
75 | | * // JobTask implementation. |
76 | | * void Run(JobDelegate* delegate) override { |
77 | | * while (!delegate->ShouldYield()) { |
78 | | * // Smallest unit of work. |
79 | | * auto work_item = worker_queue_.TakeWorkItem(); // Thread safe. |
80 | | * if (!work_item) return; |
81 | | * ProcessWork(work_item); |
82 | | * } |
83 | | * } |
84 | | * |
85 | | * size_t GetMaxConcurrency() const override { |
86 | | * return worker_queue_.GetSize(); // Thread safe. |
87 | | * } |
88 | | * }; |
89 | | * |
90 | | * // ... |
91 | | * auto handle = PostJob(TaskPriority::kUserVisible, |
92 | | * std::make_unique<MyJobTask>(...)); |
93 | | * handle->Join(); |
94 | | * \endcode |
95 | | * |
96 | | * `PostJob()` and methods of the returned JobHandle/JobDelegate, must never |
97 | | * be called while holding a lock that could be acquired by `JobTask::Run()` |
98 | | * or `JobTask::GetMaxConcurrency()` -- that could result in a deadlock. This |
99 | | * is because (1) `JobTask::GetMaxConcurrency()` may be invoked while holding |
100 | | * internal lock (A), hence `JobTask::GetMaxConcurrency()` can only use a lock |
101 | | * (B) if that lock is *never* held while calling back into `JobHandle` from |
102 | | * any thread (A=>B/B=>A deadlock) and (2) `JobTask::Run()` or |
103 | | * `JobTask::GetMaxConcurrency()` may be invoked synchronously from |
104 | | * `JobHandle` (B=>JobHandle::foo=>B deadlock). |
105 | | * |
106 | | * A sufficient `PostJob()` implementation that uses the default Job provided |
107 | | * in libplatform looks like: |
108 | | * \code |
109 | | * std::unique_ptr<JobHandle> PostJob( |
110 | | * TaskPriority priority, std::unique_ptr<JobTask> job_task) override { |
111 | | * return std::make_unique<DefaultJobHandle>( |
112 | | * std::make_shared<DefaultJobState>( |
113 | | * this, std::move(job_task), kNumThreads)); |
114 | | * } |
115 | | * \endcode |
116 | | */ |
117 | | virtual std::unique_ptr<JobHandle> PostJob( |
118 | 0 | TaskPriority priority, std::unique_ptr<JobTask> job_task) { |
119 | 0 | return nullptr; |
120 | 0 | } |
121 | | |
122 | | /** |
123 | | * Returns an instance of a `TracingController`. This must be non-nullptr. The |
124 | | * default implementation returns an empty `TracingController` that consumes |
125 | | * trace data without effect. |
126 | | */ |
127 | | virtual TracingController* GetTracingController(); |
128 | | }; |
129 | | |
130 | | /** |
131 | | * Process-global initialization of the garbage collector. Must be called before |
132 | | * creating a Heap. |
133 | | * |
134 | | * Can be called multiple times when paired with `ShutdownProcess()`. |
135 | | * |
136 | | * \param page_allocator The allocator used for maintaining meta data. Must stay |
137 | | * always alive and not change between multiple calls to InitializeProcess. If |
138 | | * no allocator is provided, a default internal version will be used. |
139 | | * \param desired_heap_size Desired amount of virtual address space to reserve |
140 | | * for the heap, in bytes. Actual size will be clamped to minimum and maximum |
141 | | * values based on compile-time settings and may be rounded up. If this |
142 | | * parameter is zero, a default value will be used. |
143 | | */ |
144 | | V8_EXPORT void InitializeProcess(PageAllocator* page_allocator = nullptr, |
145 | | size_t desired_heap_size = 0); |
146 | | |
147 | | /** |
148 | | * Must be called after destroying the last used heap. Some process-global |
149 | | * metadata may not be returned and reused upon a subsequent |
150 | | * `InitializeProcess()` call. |
151 | | */ |
152 | | V8_EXPORT void ShutdownProcess(); |
153 | | |
154 | | namespace internal { |
155 | | |
156 | | V8_EXPORT void Fatal(const std::string& reason = std::string(), |
157 | | const SourceLocation& = SourceLocation::Current()); |
158 | | |
159 | | } // namespace internal |
160 | | |
161 | | } // namespace cppgc |
162 | | |
163 | | #endif // INCLUDE_CPPGC_PLATFORM_H_ |