1 |
|
|
#ifndef SRC_NODE_PLATFORM_H_ |
2 |
|
|
#define SRC_NODE_PLATFORM_H_ |
3 |
|
|
|
4 |
|
|
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS |
5 |
|
|
|
6 |
|
|
#include <queue> |
7 |
|
|
#include <unordered_map> |
8 |
|
|
#include <vector> |
9 |
|
|
#include <functional> |
10 |
|
|
|
11 |
|
|
#include "libplatform/libplatform.h" |
12 |
|
|
#include "node.h" |
13 |
|
|
#include "node_mutex.h" |
14 |
|
|
#include "uv.h" |
15 |
|
|
|
16 |
|
|
namespace node { |
17 |
|
|
|
18 |
|
|
class NodePlatform; |
19 |
|
|
class IsolateData; |
20 |
|
|
class PerIsolatePlatformData; |
21 |
|
|
|
22 |
|
|
template <class T> |
23 |
|
|
class TaskQueue { |
24 |
|
|
public: |
25 |
|
|
TaskQueue(); |
26 |
|
24888 |
~TaskQueue() = default; |
27 |
|
|
|
28 |
|
|
void Push(std::unique_ptr<T> task); |
29 |
|
|
std::unique_ptr<T> Pop(); |
30 |
|
|
std::unique_ptr<T> BlockingPop(); |
31 |
|
|
std::queue<std::unique_ptr<T>> PopAll(); |
32 |
|
|
void NotifyOfCompletion(); |
33 |
|
|
void BlockingDrain(); |
34 |
|
|
void Stop(); |
35 |
|
|
|
36 |
|
|
private: |
37 |
|
|
Mutex lock_; |
38 |
|
|
ConditionVariable tasks_available_; |
39 |
|
|
ConditionVariable tasks_drained_; |
40 |
|
|
int outstanding_tasks_; |
41 |
|
|
bool stopped_; |
42 |
|
|
std::queue<std::unique_ptr<T>> task_queue_; |
43 |
|
|
}; |
44 |
|
|
|
45 |
|
|
struct DelayedTask { |
46 |
|
|
std::unique_ptr<v8::Task> task; |
47 |
|
|
uv_timer_t timer; |
48 |
|
|
double timeout; |
49 |
|
|
std::shared_ptr<PerIsolatePlatformData> platform_data; |
50 |
|
|
}; |
51 |
|
|
|
52 |
|
|
// This acts as the foreground task runner for a given Isolate. |
53 |
|
|
class PerIsolatePlatformData : |
54 |
|
|
public IsolatePlatformDelegate, |
55 |
|
|
public v8::TaskRunner, |
56 |
|
|
public std::enable_shared_from_this<PerIsolatePlatformData> { |
57 |
|
|
public: |
58 |
|
|
PerIsolatePlatformData(v8::Isolate* isolate, uv_loop_t* loop); |
59 |
|
|
~PerIsolatePlatformData() override; |
60 |
|
|
|
61 |
|
|
std::shared_ptr<v8::TaskRunner> GetForegroundTaskRunner() override; |
62 |
|
|
void PostTask(std::unique_ptr<v8::Task> task) override; |
63 |
|
|
void PostIdleTask(std::unique_ptr<v8::IdleTask> task) override; |
64 |
|
|
void PostDelayedTask(std::unique_ptr<v8::Task> task, |
65 |
|
|
double delay_in_seconds) override; |
66 |
|
|
bool IdleTasksEnabled() override { return false; } |
67 |
|
|
|
68 |
|
|
// Non-nestable tasks are treated like regular tasks. |
69 |
|
17541 |
bool NonNestableTasksEnabled() const override { return true; } |
70 |
|
|
bool NonNestableDelayedTasksEnabled() const override { return true; } |
71 |
|
|
void PostNonNestableTask(std::unique_ptr<v8::Task> task) override; |
72 |
|
|
void PostNonNestableDelayedTask(std::unique_ptr<v8::Task> task, |
73 |
|
|
double delay_in_seconds) override; |
74 |
|
|
|
75 |
|
|
void AddShutdownCallback(void (*callback)(void*), void* data); |
76 |
|
|
void Shutdown(); |
77 |
|
|
|
78 |
|
|
// Returns true if work was dispatched or executed. New tasks that are |
79 |
|
|
// posted during flushing of the queue are postponed until the next |
80 |
|
|
// flushing. |
81 |
|
|
bool FlushForegroundTasksInternal(); |
82 |
|
|
|
83 |
|
|
const uv_loop_t* event_loop() const { return loop_; } |
84 |
|
|
|
85 |
|
|
private: |
86 |
|
|
void DeleteFromScheduledTasks(DelayedTask* task); |
87 |
|
|
void DecreaseHandleCount(); |
88 |
|
|
|
89 |
|
|
static void FlushTasks(uv_async_t* handle); |
90 |
|
|
void RunForegroundTask(std::unique_ptr<v8::Task> task); |
91 |
|
|
static void RunForegroundTask(uv_timer_t* timer); |
92 |
|
|
|
93 |
|
|
struct ShutdownCallback { |
94 |
|
|
void (*cb)(void*); |
95 |
|
|
void* data; |
96 |
|
|
}; |
97 |
|
|
typedef std::vector<ShutdownCallback> ShutdownCbList; |
98 |
|
|
ShutdownCbList shutdown_callbacks_; |
99 |
|
|
// shared_ptr to self to keep this object alive during shutdown. |
100 |
|
|
std::shared_ptr<PerIsolatePlatformData> self_reference_; |
101 |
|
|
uint32_t uv_handle_count_ = 1; // 1 = flush_tasks_ |
102 |
|
|
|
103 |
|
|
v8::Isolate* const isolate_; |
104 |
|
|
uv_loop_t* const loop_; |
105 |
|
|
uv_async_t* flush_tasks_ = nullptr; |
106 |
|
|
TaskQueue<v8::Task> foreground_tasks_; |
107 |
|
|
TaskQueue<DelayedTask> foreground_delayed_tasks_; |
108 |
|
|
|
109 |
|
|
// Use a custom deleter because libuv needs to close the handle first. |
110 |
|
|
typedef std::unique_ptr<DelayedTask, void(*)(DelayedTask*)> |
111 |
|
|
DelayedTaskPointer; |
112 |
|
|
std::vector<DelayedTaskPointer> scheduled_delayed_tasks_; |
113 |
|
|
}; |
114 |
|
|
|
115 |
|
|
// This acts as the single worker thread task runner for all Isolates. |
116 |
|
|
class WorkerThreadsTaskRunner { |
117 |
|
|
public: |
118 |
|
|
explicit WorkerThreadsTaskRunner(int thread_pool_size); |
119 |
|
|
|
120 |
|
|
void PostTask(std::unique_ptr<v8::Task> task); |
121 |
|
|
void PostDelayedTask(std::unique_ptr<v8::Task> task, |
122 |
|
|
double delay_in_seconds); |
123 |
|
|
|
124 |
|
|
void BlockingDrain(); |
125 |
|
|
void Shutdown(); |
126 |
|
|
|
127 |
|
|
int NumberOfWorkerThreads() const; |
128 |
|
|
|
129 |
|
|
private: |
130 |
|
|
TaskQueue<v8::Task> pending_worker_tasks_; |
131 |
|
|
|
132 |
|
|
class DelayedTaskScheduler; |
133 |
|
|
std::unique_ptr<DelayedTaskScheduler> delayed_task_scheduler_; |
134 |
|
|
|
135 |
|
|
std::vector<std::unique_ptr<uv_thread_t>> threads_; |
136 |
|
|
}; |
137 |
|
|
|
138 |
|
|
class NodePlatform : public MultiIsolatePlatform { |
139 |
|
|
public: |
140 |
|
|
NodePlatform(int thread_pool_size, |
141 |
|
|
v8::TracingController* tracing_controller, |
142 |
|
|
v8::PageAllocator* page_allocator = nullptr); |
143 |
|
|
~NodePlatform() override; |
144 |
|
|
|
145 |
|
|
void DrainTasks(v8::Isolate* isolate) override; |
146 |
|
|
void Shutdown(); |
147 |
|
|
|
148 |
|
|
// v8::Platform implementation. |
149 |
|
|
int NumberOfWorkerThreads() override; |
150 |
|
|
void CallOnWorkerThread(std::unique_ptr<v8::Task> task) override; |
151 |
|
|
void CallDelayedOnWorkerThread(std::unique_ptr<v8::Task> task, |
152 |
|
|
double delay_in_seconds) override; |
153 |
|
|
bool IdleTasksEnabled(v8::Isolate* isolate) override; |
154 |
|
|
double MonotonicallyIncreasingTime() override; |
155 |
|
|
double CurrentClockTimeMillis() override; |
156 |
|
|
v8::TracingController* GetTracingController() override; |
157 |
|
|
bool FlushForegroundTasks(v8::Isolate* isolate) override; |
158 |
|
|
std::unique_ptr<v8::JobHandle> PostJob( |
159 |
|
|
v8::TaskPriority priority, |
160 |
|
|
std::unique_ptr<v8::JobTask> job_task) override; |
161 |
|
|
|
162 |
|
|
void RegisterIsolate(v8::Isolate* isolate, uv_loop_t* loop) override; |
163 |
|
|
void RegisterIsolate(v8::Isolate* isolate, |
164 |
|
|
IsolatePlatformDelegate* delegate) override; |
165 |
|
|
|
166 |
|
|
void UnregisterIsolate(v8::Isolate* isolate) override; |
167 |
|
|
void AddIsolateFinishedCallback(v8::Isolate* isolate, |
168 |
|
|
void (*callback)(void*), void* data) override; |
169 |
|
|
|
170 |
|
|
std::shared_ptr<v8::TaskRunner> GetForegroundTaskRunner( |
171 |
|
|
v8::Isolate* isolate) override; |
172 |
|
|
|
173 |
|
|
Platform::StackTracePrinter GetStackTracePrinter() override; |
174 |
|
|
v8::PageAllocator* GetPageAllocator() override; |
175 |
|
|
|
176 |
|
|
private: |
177 |
|
|
IsolatePlatformDelegate* ForIsolate(v8::Isolate* isolate); |
178 |
|
|
std::shared_ptr<PerIsolatePlatformData> ForNodeIsolate(v8::Isolate* isolate); |
179 |
|
|
|
180 |
|
|
Mutex per_isolate_mutex_; |
181 |
|
|
using DelegatePair = std::pair< |
182 |
|
|
IsolatePlatformDelegate*, std::shared_ptr<PerIsolatePlatformData>>; |
183 |
|
|
std::unordered_map<v8::Isolate*, DelegatePair> per_isolate_; |
184 |
|
|
|
185 |
|
|
v8::TracingController* tracing_controller_; |
186 |
|
|
v8::PageAllocator* page_allocator_; |
187 |
|
|
std::shared_ptr<WorkerThreadsTaskRunner> worker_thread_task_runner_; |
188 |
|
|
bool has_shut_down_ = false; |
189 |
|
|
}; |
190 |
|
|
|
191 |
|
|
} // namespace node |
192 |
|
|
|
193 |
|
|
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS |
194 |
|
|
|
195 |
|
|
#endif // SRC_NODE_PLATFORM_H_ |