Skip to content

Commit bf8068e

Browse files
addaleaxrvagg
authored andcommitted
src: prepare v8 platform for multi-isolate support
This splits the task queue used for asynchronous tasks scheduled by V8 in per-isolate queues, so that multiple threads can be supported. Backport-PR-URL: #20901 Original-PR-URL: ayojs/ayo#89 Original-Reviewed-By: Timothy Gu <[email protected]> PR-URL: #16700 Reviewed-By: James M Snell <[email protected]>
1 parent 0b2f527 commit bf8068e

File tree

11 files changed

+283
-103
lines changed

11 files changed

+283
-103
lines changed

src/env-inl.h

Lines changed: 7 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -37,41 +37,9 @@
3737

3838
namespace node {
3939

40-
inline IsolateData::IsolateData(v8::Isolate* isolate, uv_loop_t* event_loop,
41-
uint32_t* zero_fill_field) :
42-
43-
// Create string and private symbol properties as internalized one byte strings.
44-
//
45-
// Internalized because it makes property lookups a little faster and because
46-
// the string is created in the old space straight away. It's going to end up
47-
// in the old space sooner or later anyway but now it doesn't go through
48-
// v8::Eternal's new space handling first.
49-
//
50-
// One byte because our strings are ASCII and we can safely skip V8's UTF-8
51-
// decoding step. It's a one-time cost, but why pay it when you don't have to?
52-
#define V(PropertyName, StringValue) \
53-
PropertyName ## _( \
54-
isolate, \
55-
v8::Private::New( \
56-
isolate, \
57-
v8::String::NewFromOneByte( \
58-
isolate, \
59-
reinterpret_cast<const uint8_t*>(StringValue), \
60-
v8::NewStringType::kInternalized, \
61-
sizeof(StringValue) - 1).ToLocalChecked())),
62-
PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V)
63-
#undef V
64-
#define V(PropertyName, StringValue) \
65-
PropertyName ## _( \
66-
isolate, \
67-
v8::String::NewFromOneByte( \
68-
isolate, \
69-
reinterpret_cast<const uint8_t*>(StringValue), \
70-
v8::NewStringType::kInternalized, \
71-
sizeof(StringValue) - 1).ToLocalChecked()),
72-
PER_ISOLATE_STRING_PROPERTIES(V)
73-
#undef V
74-
event_loop_(event_loop), zero_fill_field_(zero_fill_field) {}
40+
inline v8::Isolate* IsolateData::isolate() const {
41+
return isolate_;
42+
}
7543

7644
inline uv_loop_t* IsolateData::event_loop() const {
7745
return event_loop_;
@@ -81,6 +49,10 @@ inline uint32_t* IsolateData::zero_fill_field() const {
8149
return zero_fill_field_;
8250
}
8351

52+
inline MultiIsolatePlatform* IsolateData::platform() const {
53+
return platform_;
54+
}
55+
8456
inline Environment::AsyncHooks::AsyncHooks()
8557
: async_ids_stack_(env()->isolate(), 16 * 2),
8658
fields_(env()->isolate(), kFieldsCount),
@@ -93,10 +65,6 @@ inline Environment::AsyncHooks::AsyncHooks()
9365
// which is different from a default context.
9466
async_id_fields_[AsyncHooks::kDefaultTriggerAsyncId] = -1;
9567

96-
// kAsyncIdCounter should start at 1 because that'll be the id the execution
97-
// context during bootstrap (code that runs before entering uv_run()).
98-
async_id_fields_[AsyncHooks::kAsyncIdCounter] = 1;
99-
10068
// Create all the provider strings that will be passed to JS. Place them in
10169
// an array so the array index matches the PROVIDER id offset. This way the
10270
// strings can be retrieved quickly.

src/env.cc

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
#include "node_internals.h"
22
#include "async_wrap.h"
33
#include "v8-profiler.h"
4+
#include "node_buffer.h"
5+
#include "req-wrap-inl.h"
6+
#include "node_platform.h"
7+
8+
#if defined(_MSC_VER)
9+
#define getpid GetCurrentProcessId
10+
#else
11+
#include <unistd.h>
12+
#endif
413

514
#include <stdio.h>
615
#include <algorithm>
@@ -10,10 +19,62 @@ namespace node {
1019
using v8::Context;
1120
using v8::FunctionTemplate;
1221
using v8::HandleScope;
22+
using v8::Isolate;
1323
using v8::Local;
1424
using v8::Message;
25+
using v8::Private;
1526
using v8::StackFrame;
1627
using v8::StackTrace;
28+
using v8::String;
29+
30+
IsolateData::IsolateData(Isolate* isolate,
31+
uv_loop_t* event_loop,
32+
MultiIsolatePlatform* platform,
33+
uint32_t* zero_fill_field) :
34+
35+
// Create string and private symbol properties as internalized one byte strings.
36+
//
37+
// Internalized because it makes property lookups a little faster and because
38+
// the string is created in the old space straight away. It's going to end up
39+
// in the old space sooner or later anyway but now it doesn't go through
40+
// v8::Eternal's new space handling first.
41+
//
42+
// One byte because our strings are ASCII and we can safely skip V8's UTF-8
43+
// decoding step. It's a one-time cost, but why pay it when you don't have to?
44+
#define V(PropertyName, StringValue) \
45+
PropertyName ## _( \
46+
isolate, \
47+
Private::New( \
48+
isolate, \
49+
String::NewFromOneByte( \
50+
isolate, \
51+
reinterpret_cast<const uint8_t*>(StringValue), \
52+
v8::NewStringType::kInternalized, \
53+
sizeof(StringValue) - 1).ToLocalChecked())),
54+
PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V)
55+
#undef V
56+
#define V(PropertyName, StringValue) \
57+
PropertyName ## _( \
58+
isolate, \
59+
String::NewFromOneByte( \
60+
isolate, \
61+
reinterpret_cast<const uint8_t*>(StringValue), \
62+
v8::NewStringType::kInternalized, \
63+
sizeof(StringValue) - 1).ToLocalChecked()),
64+
PER_ISOLATE_STRING_PROPERTIES(V)
65+
#undef V
66+
isolate_(isolate),
67+
event_loop_(event_loop),
68+
zero_fill_field_(zero_fill_field),
69+
platform_(platform) {
70+
if (platform_ != nullptr)
71+
platform_->RegisterIsolate(this, event_loop);
72+
}
73+
74+
IsolateData::~IsolateData() {
75+
if (platform_ != nullptr)
76+
platform_->UnregisterIsolate(this);
77+
}
1778

1879
void Environment::Start(int argc,
1980
const char* const* argv,

src/env.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -347,10 +347,13 @@ class Environment;
347347

348348
class IsolateData {
349349
public:
350-
inline IsolateData(v8::Isolate* isolate, uv_loop_t* event_loop,
351-
uint32_t* zero_fill_field = nullptr);
350+
IsolateData(v8::Isolate* isolate, uv_loop_t* event_loop,
351+
MultiIsolatePlatform* platform = nullptr,
352+
uint32_t* zero_fill_field = nullptr);
353+
~IsolateData();
352354
inline uv_loop_t* event_loop() const;
353355
inline uint32_t* zero_fill_field() const;
356+
inline MultiIsolatePlatform* platform() const;
354357

355358
#define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
356359
#define VS(PropertyName, StringValue) V(v8::String, PropertyName)
@@ -363,6 +366,7 @@ class IsolateData {
363366
#undef VP
364367

365368
std::unordered_map<nghttp2_rcbuf*, v8::Eternal<v8::String>> http2_static_strs;
369+
inline v8::Isolate* isolate() const;
366370

367371
private:
368372
#define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
@@ -375,8 +379,10 @@ class IsolateData {
375379
#undef VS
376380
#undef VP
377381

382+
v8::Isolate* const isolate_;
378383
uv_loop_t* const event_loop_;
379384
uint32_t* const zero_fill_field_;
385+
MultiIsolatePlatform* platform_;
380386

381387
DISALLOW_COPY_AND_ASSIGN(IsolateData);
382388
};

src/inspector_agent.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ class NodeInspectorClient : public V8InspectorClient {
314314
terminated_ = false;
315315
running_nested_loop_ = true;
316316
while (!terminated_ && channel_->waitForFrontendMessage()) {
317-
platform_->FlushForegroundTasksInternal();
317+
platform_->FlushForegroundTasks(env_->isolate());
318318
}
319319
terminated_ = false;
320320
running_nested_loop_ = false;

src/node.cc

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -273,17 +273,17 @@ node::DebugOptions debug_options;
273273

274274
static struct {
275275
#if NODE_USE_V8_PLATFORM
276-
void Initialize(int thread_pool_size, uv_loop_t* loop) {
276+
void Initialize(int thread_pool_size) {
277277
if (trace_enabled) {
278278
tracing_agent_.reset(new tracing::Agent(trace_file_pattern));
279-
platform_ = new NodePlatform(thread_pool_size, loop,
279+
platform_ = new NodePlatform(thread_pool_size,
280280
tracing_agent_->GetTracingController());
281281
V8::InitializePlatform(platform_);
282282
tracing::TraceEventHelper::SetTracingController(
283283
tracing_agent_->GetTracingController());
284284
} else {
285285
tracing_agent_.reset(nullptr);
286-
platform_ = new NodePlatform(thread_pool_size, loop, nullptr);
286+
platform_ = new NodePlatform(thread_pool_size, nullptr);
287287
V8::InitializePlatform(platform_);
288288
tracing::TraceEventHelper::SetTracingController(
289289
new v8::TracingController());
@@ -297,8 +297,8 @@ static struct {
297297
tracing_agent_.reset(nullptr);
298298
}
299299

300-
void DrainVMTasks() {
301-
platform_->DrainBackgroundTasks();
300+
void DrainVMTasks(Isolate* isolate) {
301+
platform_->DrainBackgroundTasks(isolate);
302302
}
303303

304304
#if HAVE_INSPECTOR
@@ -323,12 +323,16 @@ static struct {
323323
tracing_agent_->Stop();
324324
}
325325

326+
NodePlatform* Platform() {
327+
return platform_;
328+
}
329+
326330
std::unique_ptr<tracing::Agent> tracing_agent_;
327331
NodePlatform* platform_;
328332
#else // !NODE_USE_V8_PLATFORM
329-
void Initialize(int thread_pool_size, uv_loop_t* loop) {}
333+
void Initialize(int thread_pool_size) {}
330334
void Dispose() {}
331-
void DrainVMTasks() {}
335+
void DrainVMTasks(Isolate* isolate) {}
332336
bool StartInspector(Environment *env, const char* script_path,
333337
const node::DebugOptions& options) {
334338
env->ThrowError("Node compiled with NODE_USE_V8_PLATFORM=0");
@@ -340,6 +344,10 @@ static struct {
340344
"so event tracing is not available.\n");
341345
}
342346
void StopTracingAgent() {}
347+
348+
NodePlatform* Platform() {
349+
return nullptr;
350+
}
343351
#endif // !NODE_USE_V8_PLATFORM
344352

345353
#if !NODE_USE_V8_PLATFORM || !HAVE_INSPECTOR
@@ -4733,7 +4741,14 @@ int EmitExit(Environment* env) {
47334741

47344742

47354743
IsolateData* CreateIsolateData(Isolate* isolate, uv_loop_t* loop) {
4736-
return new IsolateData(isolate, loop);
4744+
return new IsolateData(isolate, loop, nullptr);
4745+
}
4746+
4747+
IsolateData* CreateIsolateData(
4748+
Isolate* isolate,
4749+
uv_loop_t* loop,
4750+
MultiIsolatePlatform* platform) {
4751+
return new IsolateData(isolate, loop, platform);
47374752
}
47384753

47394754

@@ -4801,7 +4816,7 @@ inline int Start(Isolate* isolate, IsolateData* isolate_data,
48014816
do {
48024817
uv_run(env.event_loop(), UV_RUN_DEFAULT);
48034818

4804-
v8_platform.DrainVMTasks();
4819+
v8_platform.DrainVMTasks(isolate);
48054820

48064821
more = uv_loop_alive(env.event_loop());
48074822
if (more)
@@ -4822,7 +4837,7 @@ inline int Start(Isolate* isolate, IsolateData* isolate_data,
48224837
RunAtExit(&env);
48234838
uv_key_delete(&thread_local_env);
48244839

4825-
v8_platform.DrainVMTasks();
4840+
v8_platform.DrainVMTasks(isolate);
48264841
WaitForInspectorDisconnect(&env);
48274842
#if defined(LEAK_SANITIZER)
48284843
__lsan_do_leak_check();
@@ -4865,7 +4880,11 @@ inline int Start(uv_loop_t* event_loop,
48654880
Locker locker(isolate);
48664881
Isolate::Scope isolate_scope(isolate);
48674882
HandleScope handle_scope(isolate);
4868-
IsolateData isolate_data(isolate, event_loop, allocator.zero_fill_field());
4883+
IsolateData isolate_data(
4884+
isolate,
4885+
event_loop,
4886+
v8_platform.Platform(),
4887+
allocator.zero_fill_field());
48694888
exit_code = Start(isolate, &isolate_data, argc, argv, exec_argc, exec_argv);
48704889
}
48714890

@@ -4912,7 +4931,7 @@ int Start(int argc, char** argv) {
49124931
V8::SetEntropySource(crypto::EntropySource);
49134932
#endif // HAVE_OPENSSL
49144933

4915-
v8_platform.Initialize(v8_thread_pool_size, uv_default_loop());
4934+
v8_platform.Initialize(v8_thread_pool_size);
49164935
// Enable tracing when argv has --trace-events-enabled.
49174936
if (trace_enabled) {
49184937
fprintf(stderr, "Warning: Trace event is an experimental feature "

src/node.h

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
#endif
6262

6363
#include "v8.h" // NOLINT(build/include_order)
64+
#include "v8-platform.h" // NOLINT(build/include_order)
6465
#include "node_version.h" // NODE_MODULE_VERSION
6566

6667
#define NODE_MAKE_VERSION(major, minor, patch) \
@@ -208,8 +209,27 @@ NODE_EXTERN void Init(int* argc,
208209
class IsolateData;
209210
class Environment;
210211

211-
NODE_EXTERN IsolateData* CreateIsolateData(v8::Isolate* isolate,
212-
struct uv_loop_s* loop);
212+
class MultiIsolatePlatform : public v8::Platform {
213+
public:
214+
virtual ~MultiIsolatePlatform() { }
215+
virtual void DrainBackgroundTasks(v8::Isolate* isolate) = 0;
216+
217+
// These will be called by the `IsolateData` creation/destruction functions.
218+
virtual void RegisterIsolate(IsolateData* isolate_data,
219+
struct uv_loop_s* loop) = 0;
220+
virtual void UnregisterIsolate(IsolateData* isolate_data) = 0;
221+
};
222+
223+
// If `platform` is passed, it will be used to register new Worker instances.
224+
// It can be `nullptr`, in which case creating new Workers inside of
225+
// Environments that use this `IsolateData` will not work.
226+
NODE_EXTERN IsolateData* CreateIsolateData(
227+
v8::Isolate* isolate,
228+
struct uv_loop_s* loop);
229+
NODE_EXTERN IsolateData* CreateIsolateData(
230+
v8::Isolate* isolate,
231+
struct uv_loop_s* loop,
232+
MultiIsolatePlatform* platform);
213233
NODE_EXTERN void FreeIsolateData(IsolateData* isolate_data);
214234

215235
NODE_EXTERN Environment* CreateEnvironment(IsolateData* isolate_data,

0 commit comments

Comments
 (0)