Skip to content

Commit 936c0b2

Browse files
addaleaxMylesBorins
authored andcommitted
src: implement v8::TaskRunner API in NodePlatform
V8 is switching APIs for scheduling tasks. Implement the new APIs. Fixes: nodejs/node-v8#24 Refs: v8/v8@c690f54 PR-URL: #17134 Fixes: nodejs/node-v8#24 Reviewed-By: Franziska Hinkelmann <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent 0411572 commit 936c0b2

File tree

2 files changed

+119
-44
lines changed

2 files changed

+119
-44
lines changed

src/node_platform.cc

+80-35
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,43 @@ static void BackgroundRunner(void* data) {
2424
}
2525
}
2626

27+
BackgroundTaskRunner::BackgroundTaskRunner(int thread_pool_size) {
28+
for (int i = 0; i < thread_pool_size; i++) {
29+
std::unique_ptr<uv_thread_t> t { new uv_thread_t() };
30+
if (uv_thread_create(t.get(), BackgroundRunner, &background_tasks_) != 0)
31+
break;
32+
threads_.push_back(std::move(t));
33+
}
34+
}
35+
36+
void BackgroundTaskRunner::PostTask(std::unique_ptr<Task> task) {
37+
background_tasks_.Push(std::move(task));
38+
}
39+
40+
void BackgroundTaskRunner::PostIdleTask(std::unique_ptr<v8::IdleTask> task) {
41+
UNREACHABLE();
42+
}
43+
44+
void BackgroundTaskRunner::PostDelayedTask(std::unique_ptr<v8::Task> task,
45+
double delay_in_seconds) {
46+
UNREACHABLE();
47+
}
48+
49+
void BackgroundTaskRunner::BlockingDrain() {
50+
background_tasks_.BlockingDrain();
51+
}
52+
53+
void BackgroundTaskRunner::Shutdown() {
54+
background_tasks_.Stop();
55+
for (size_t i = 0; i < threads_.size(); i++) {
56+
CHECK_EQ(0, uv_thread_join(threads_[i].get()));
57+
}
58+
}
59+
60+
size_t BackgroundTaskRunner::NumberOfAvailableBackgroundThreads() const {
61+
return threads_.size();
62+
}
63+
2764
PerIsolatePlatformData::PerIsolatePlatformData(
2865
v8::Isolate* isolate, uv_loop_t* loop)
2966
: isolate_(isolate), loop_(loop) {
@@ -38,17 +75,20 @@ void PerIsolatePlatformData::FlushTasks(uv_async_t* handle) {
3875
platform_data->FlushForegroundTasksInternal();
3976
}
4077

41-
void PerIsolatePlatformData::CallOnForegroundThread(
42-
std::unique_ptr<Task> task) {
78+
void PerIsolatePlatformData::PostIdleTask(std::unique_ptr<v8::IdleTask> task) {
79+
UNREACHABLE();
80+
}
81+
82+
void PerIsolatePlatformData::PostTask(std::unique_ptr<Task> task) {
4383
foreground_tasks_.Push(std::move(task));
4484
uv_async_send(flush_tasks_);
4585
}
4686

47-
void PerIsolatePlatformData::CallDelayedOnForegroundThread(
48-
std::unique_ptr<Task> task, double delay_in_seconds) {
87+
void PerIsolatePlatformData::PostDelayedTask(
88+
std::unique_ptr<Task> task, double delay_in_seconds) {
4989
std::unique_ptr<DelayedTask> delayed(new DelayedTask());
5090
delayed->task = std::move(task);
51-
delayed->platform_data = this;
91+
delayed->platform_data = shared_from_this();
5292
delayed->timeout = delay_in_seconds;
5393
foreground_delayed_tasks_.Push(std::move(delayed));
5494
uv_async_send(flush_tasks_);
@@ -80,49 +120,43 @@ NodePlatform::NodePlatform(int thread_pool_size,
80120
TracingController* controller = new TracingController();
81121
tracing_controller_.reset(controller);
82122
}
83-
for (int i = 0; i < thread_pool_size; i++) {
84-
uv_thread_t* t = new uv_thread_t();
85-
if (uv_thread_create(t, BackgroundRunner, &background_tasks_) != 0) {
86-
delete t;
87-
break;
88-
}
89-
threads_.push_back(std::unique_ptr<uv_thread_t>(t));
90-
}
123+
background_task_runner_ =
124+
std::make_shared<BackgroundTaskRunner>(thread_pool_size);
91125
}
92126

93127
void NodePlatform::RegisterIsolate(IsolateData* isolate_data, uv_loop_t* loop) {
94128
Isolate* isolate = isolate_data->isolate();
95129
Mutex::ScopedLock lock(per_isolate_mutex_);
96-
PerIsolatePlatformData* existing = per_isolate_[isolate];
97-
if (existing != nullptr)
130+
std::shared_ptr<PerIsolatePlatformData> existing = per_isolate_[isolate];
131+
if (existing) {
98132
existing->ref();
99-
else
100-
per_isolate_[isolate] = new PerIsolatePlatformData(isolate, loop);
133+
} else {
134+
per_isolate_[isolate] =
135+
std::make_shared<PerIsolatePlatformData>(isolate, loop);
136+
}
101137
}
102138

103139
void NodePlatform::UnregisterIsolate(IsolateData* isolate_data) {
104140
Isolate* isolate = isolate_data->isolate();
105141
Mutex::ScopedLock lock(per_isolate_mutex_);
106-
PerIsolatePlatformData* existing = per_isolate_[isolate];
107-
CHECK_NE(existing, nullptr);
142+
std::shared_ptr<PerIsolatePlatformData> existing = per_isolate_[isolate];
143+
CHECK(existing);
108144
if (existing->unref() == 0) {
109-
delete existing;
110145
per_isolate_.erase(isolate);
111146
}
112147
}
113148

114149
void NodePlatform::Shutdown() {
115-
background_tasks_.Stop();
116-
for (size_t i = 0; i < threads_.size(); i++) {
117-
CHECK_EQ(0, uv_thread_join(threads_[i].get()));
150+
background_task_runner_->Shutdown();
151+
152+
{
153+
Mutex::ScopedLock lock(per_isolate_mutex_);
154+
per_isolate_.clear();
118155
}
119-
Mutex::ScopedLock lock(per_isolate_mutex_);
120-
for (const auto& pair : per_isolate_)
121-
delete pair.second;
122156
}
123157

124158
size_t NodePlatform::NumberOfAvailableBackgroundThreads() {
125-
return threads_.size();
159+
return background_task_runner_->NumberOfAvailableBackgroundThreads();
126160
}
127161

128162
void PerIsolatePlatformData::RunForegroundTask(std::unique_ptr<Task> task) {
@@ -155,14 +189,14 @@ void PerIsolatePlatformData::CancelPendingDelayedTasks() {
155189
}
156190

157191
void NodePlatform::DrainBackgroundTasks(Isolate* isolate) {
158-
PerIsolatePlatformData* per_isolate = ForIsolate(isolate);
192+
std::shared_ptr<PerIsolatePlatformData> per_isolate = ForIsolate(isolate);
159193

160194
do {
161195
// Right now, there is no way to drain only background tasks associated
162196
// with a specific isolate, so this sometimes does more work than
163197
// necessary. In the long run, that functionality is probably going to
164198
// be available anyway, though.
165-
background_tasks_.BlockingDrain();
199+
background_task_runner_->BlockingDrain();
166200
} while (per_isolate->FlushForegroundTasksInternal());
167201
}
168202

@@ -198,24 +232,25 @@ bool PerIsolatePlatformData::FlushForegroundTasksInternal() {
198232

199233
void NodePlatform::CallOnBackgroundThread(Task* task,
200234
ExpectedRuntime expected_runtime) {
201-
background_tasks_.Push(std::unique_ptr<Task>(task));
235+
background_task_runner_->PostTask(std::unique_ptr<Task>(task));
202236
}
203237

204-
PerIsolatePlatformData* NodePlatform::ForIsolate(Isolate* isolate) {
238+
std::shared_ptr<PerIsolatePlatformData>
239+
NodePlatform::ForIsolate(Isolate* isolate) {
205240
Mutex::ScopedLock lock(per_isolate_mutex_);
206-
PerIsolatePlatformData* data = per_isolate_[isolate];
207-
CHECK_NE(data, nullptr);
241+
std::shared_ptr<PerIsolatePlatformData> data = per_isolate_[isolate];
242+
CHECK(data);
208243
return data;
209244
}
210245

211246
void NodePlatform::CallOnForegroundThread(Isolate* isolate, Task* task) {
212-
ForIsolate(isolate)->CallOnForegroundThread(std::unique_ptr<Task>(task));
247+
ForIsolate(isolate)->PostTask(std::unique_ptr<Task>(task));
213248
}
214249

215250
void NodePlatform::CallDelayedOnForegroundThread(Isolate* isolate,
216251
Task* task,
217252
double delay_in_seconds) {
218-
ForIsolate(isolate)->CallDelayedOnForegroundThread(
253+
ForIsolate(isolate)->PostDelayedTask(
219254
std::unique_ptr<Task>(task), delay_in_seconds);
220255
}
221256

@@ -229,6 +264,16 @@ void NodePlatform::CancelPendingDelayedTasks(v8::Isolate* isolate) {
229264

230265
bool NodePlatform::IdleTasksEnabled(Isolate* isolate) { return false; }
231266

267+
std::shared_ptr<v8::TaskRunner>
268+
NodePlatform::GetBackgroundTaskRunner(Isolate* isolate) {
269+
return background_task_runner_;
270+
}
271+
272+
std::shared_ptr<v8::TaskRunner>
273+
NodePlatform::GetForegroundTaskRunner(Isolate* isolate) {
274+
return ForIsolate(isolate);
275+
}
276+
232277
double NodePlatform::MonotonicallyIncreasingTime() {
233278
// Convert nanos to seconds.
234279
return uv_hrtime() / 1e9;

src/node_platform.h

+39-9
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,22 @@ struct DelayedTask {
4343
std::unique_ptr<v8::Task> task;
4444
uv_timer_t timer;
4545
double timeout;
46-
PerIsolatePlatformData* platform_data;
46+
std::shared_ptr<PerIsolatePlatformData> platform_data;
4747
};
4848

49-
class PerIsolatePlatformData {
49+
// This acts as the foreground task runner for a given Isolate.
50+
class PerIsolatePlatformData :
51+
public v8::TaskRunner,
52+
public std::enable_shared_from_this<PerIsolatePlatformData> {
5053
public:
5154
PerIsolatePlatformData(v8::Isolate* isolate, uv_loop_t* loop);
5255
~PerIsolatePlatformData();
5356

54-
void CallOnForegroundThread(std::unique_ptr<v8::Task> task);
55-
void CallDelayedOnForegroundThread(std::unique_ptr<v8::Task> task,
56-
double delay_in_seconds);
57+
void PostTask(std::unique_ptr<v8::Task> task) override;
58+
void PostIdleTask(std::unique_ptr<v8::IdleTask> task) override;
59+
void PostDelayedTask(std::unique_ptr<v8::Task> task,
60+
double delay_in_seconds) override;
61+
bool IdleTasksEnabled() override { return false; };
5762

5863
void Shutdown();
5964

@@ -84,6 +89,26 @@ class PerIsolatePlatformData {
8489
std::vector<DelayedTaskPointer> scheduled_delayed_tasks_;
8590
};
8691

92+
// This acts as the single background task runner for all Isolates.
93+
class BackgroundTaskRunner : public v8::TaskRunner {
94+
public:
95+
explicit BackgroundTaskRunner(int thread_pool_size);
96+
97+
void PostTask(std::unique_ptr<v8::Task> task) override;
98+
void PostIdleTask(std::unique_ptr<v8::IdleTask> task) override;
99+
void PostDelayedTask(std::unique_ptr<v8::Task> task,
100+
double delay_in_seconds) override;
101+
bool IdleTasksEnabled() override { return false; };
102+
103+
void BlockingDrain();
104+
void Shutdown();
105+
106+
size_t NumberOfAvailableBackgroundThreads() const;
107+
private:
108+
TaskQueue<v8::Task> background_tasks_;
109+
std::vector<std::unique_ptr<uv_thread_t>> threads_;
110+
};
111+
87112
class NodePlatform : public MultiIsolatePlatform {
88113
public:
89114
NodePlatform(int thread_pool_size, v8::TracingController* tracing_controller);
@@ -109,15 +134,20 @@ class NodePlatform : public MultiIsolatePlatform {
109134
void RegisterIsolate(IsolateData* isolate_data, uv_loop_t* loop) override;
110135
void UnregisterIsolate(IsolateData* isolate_data) override;
111136

137+
std::shared_ptr<v8::TaskRunner> GetBackgroundTaskRunner(
138+
v8::Isolate* isolate) override;
139+
std::shared_ptr<v8::TaskRunner> GetForegroundTaskRunner(
140+
v8::Isolate* isolate) override;
141+
112142
private:
113-
PerIsolatePlatformData* ForIsolate(v8::Isolate* isolate);
143+
std::shared_ptr<PerIsolatePlatformData> ForIsolate(v8::Isolate* isolate);
114144

115145
Mutex per_isolate_mutex_;
116-
std::unordered_map<v8::Isolate*, PerIsolatePlatformData*> per_isolate_;
117-
TaskQueue<v8::Task> background_tasks_;
118-
std::vector<std::unique_ptr<uv_thread_t>> threads_;
146+
std::unordered_map<v8::Isolate*,
147+
std::shared_ptr<PerIsolatePlatformData>> per_isolate_;
119148

120149
std::unique_ptr<v8::TracingController> tracing_controller_;
150+
std::shared_ptr<BackgroundTaskRunner> background_task_runner_;
121151
};
122152

123153
} // namespace node

0 commit comments

Comments
 (0)