Skip to content

Commit eeede3b

Browse files
committed
domain: further abstract usage in C++
Move the majority of C++ domain-related code into JS land by introducing a top level domain callback which handles entering & exiting the domain. Move the rest of the domain necessities into their own file that creates an internal binding, to avoid exposing domain-related code on the process object. Modify an existing test slightly to better test domain-related code. PR-URL: #18291 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent e4743ab commit eeede3b

File tree

10 files changed

+72
-90
lines changed

10 files changed

+72
-90
lines changed

lib/domain.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,21 @@ process.setUncaughtExceptionCaptureCallback = function(fn) {
9494
throw err;
9595
};
9696

97+
function topLevelDomainCallback(cb, ...args) {
98+
const domain = this.domain;
99+
if (domain)
100+
domain.enter();
101+
const ret = Reflect.apply(cb, this, args);
102+
if (domain)
103+
domain.exit();
104+
return ret;
105+
}
106+
97107
// It's possible to enter one domain while already inside
98108
// another one. The stack is each entered domain.
99109
const stack = [];
100110
exports._stack = stack;
101-
process._setupDomainUse();
111+
internalBinding('domain').enable(topLevelDomainCallback);
102112

103113
function updateExceptionCapture() {
104114
if (stack.every((domain) => domain.listenerCount('error') === 0)) {

node.gyp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,7 @@
300300
'src/node_constants.cc',
301301
'src/node_contextify.cc',
302302
'src/node_debug_options.cc',
303+
'src/node_domain.cc',
303304
'src/node_file.cc',
304305
'src/node_http2.cc',
305306
'src/node_http_parser.cc',

src/env-inl.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,6 @@ inline Environment::Environment(IsolateData* isolate_data,
310310
immediate_info_(context->GetIsolate()),
311311
tick_info_(context->GetIsolate()),
312312
timer_base_(uv_now(isolate_data->event_loop())),
313-
using_domains_(false),
314313
printed_error_(false),
315314
trace_sync_io_(false),
316315
abort_on_uncaught_exception_(false),
@@ -426,14 +425,6 @@ inline uint64_t Environment::timer_base() const {
426425
return timer_base_;
427426
}
428427

429-
inline bool Environment::using_domains() const {
430-
return using_domains_;
431-
}
432-
433-
inline void Environment::set_using_domains(bool value) {
434-
using_domains_ = value;
435-
}
436-
437428
inline bool Environment::printed_error() const {
438429
return printed_error_;
439430
}

src/env.h

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,6 @@ class ModuleWrap;
9191
V(decorated_private_symbol, "node:decorated") \
9292
V(npn_buffer_private_symbol, "node:npnBuffer") \
9393
V(selected_npn_buffer_private_symbol, "node:selectedNpnBuffer") \
94-
V(domain_private_symbol, "node:domain") \
9594

9695
// Strings are per-isolate primitives but Environment proxies them
9796
// for the sake of convenience. Strings should be ASCII-only.
@@ -128,7 +127,6 @@ class ModuleWrap;
128127
V(dns_soa_string, "SOA") \
129128
V(dns_srv_string, "SRV") \
130129
V(dns_txt_string, "TXT") \
131-
V(domain_string, "domain") \
132130
V(emit_warning_string, "emitWarning") \
133131
V(exchange_string, "exchange") \
134132
V(encoding_string, "encoding") \
@@ -280,6 +278,7 @@ class ModuleWrap;
280278
V(internal_binding_cache_object, v8::Object) \
281279
V(buffer_prototype_object, v8::Object) \
282280
V(context, v8::Context) \
281+
V(domain_callback, v8::Function) \
283282
V(host_import_module_dynamically_callback, v8::Function) \
284283
V(http2ping_constructor_template, v8::ObjectTemplate) \
285284
V(http2stream_constructor_template, v8::ObjectTemplate) \
@@ -567,9 +566,6 @@ class Environment {
567566

568567
inline IsolateData* isolate_data() const;
569568

570-
inline bool using_domains() const;
571-
inline void set_using_domains(bool value);
572-
573569
inline bool printed_error() const;
574570
inline void set_printed_error(bool value);
575571

@@ -745,7 +741,6 @@ class Environment {
745741
ImmediateInfo immediate_info_;
746742
TickInfo tick_info_;
747743
const uint64_t timer_base_;
748-
bool using_domains_;
749744
bool printed_error_;
750745
bool trace_sync_io_;
751746
bool abort_on_uncaught_exception_;

src/node.cc

Lines changed: 10 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -790,62 +790,6 @@ bool ShouldAbortOnUncaughtException(Isolate* isolate) {
790790
}
791791

792792

793-
Local<Value> GetDomainProperty(Environment* env, Local<Object> object) {
794-
Local<Value> domain_v =
795-
object->GetPrivate(env->context(), env->domain_private_symbol())
796-
.ToLocalChecked();
797-
if (domain_v->IsObject()) {
798-
return domain_v;
799-
}
800-
return object->Get(env->context(), env->domain_string()).ToLocalChecked();
801-
}
802-
803-
804-
void DomainEnter(Environment* env, Local<Object> object) {
805-
Local<Value> domain_v = GetDomainProperty(env, object);
806-
if (domain_v->IsObject()) {
807-
Local<Object> domain = domain_v.As<Object>();
808-
Local<Value> enter_v = domain->Get(env->enter_string());
809-
if (enter_v->IsFunction()) {
810-
if (enter_v.As<Function>()->Call(domain, 0, nullptr).IsEmpty()) {
811-
FatalError("node::AsyncWrap::MakeCallback",
812-
"domain enter callback threw, please report this");
813-
}
814-
}
815-
}
816-
}
817-
818-
819-
void DomainExit(Environment* env, v8::Local<v8::Object> object) {
820-
Local<Value> domain_v = GetDomainProperty(env, object);
821-
if (domain_v->IsObject()) {
822-
Local<Object> domain = domain_v.As<Object>();
823-
Local<Value> exit_v = domain->Get(env->exit_string());
824-
if (exit_v->IsFunction()) {
825-
if (exit_v.As<Function>()->Call(domain, 0, nullptr).IsEmpty()) {
826-
FatalError("node::AsyncWrap::MakeCallback",
827-
"domain exit callback threw, please report this");
828-
}
829-
}
830-
}
831-
}
832-
833-
void SetupDomainUse(const FunctionCallbackInfo<Value>& args) {
834-
Environment* env = Environment::GetCurrent(args);
835-
836-
if (env->using_domains())
837-
return;
838-
env->set_using_domains(true);
839-
840-
HandleScope scope(env->isolate());
841-
842-
// Do a little housekeeping.
843-
env->process_object()->Delete(
844-
env->context(),
845-
FIXED_ONE_BYTE_STRING(args.GetIsolate(), "_setupDomainUse")).FromJust();
846-
}
847-
848-
849793
void RunMicrotasks(const FunctionCallbackInfo<Value>& args) {
850794
args.GetIsolate()->RunMicrotasks();
851795
}
@@ -982,11 +926,6 @@ InternalCallbackScope::InternalCallbackScope(Environment* env,
982926
// If you hit this assertion, you forgot to enter the v8::Context first.
983927
CHECK_EQ(Environment::GetCurrent(env->isolate()), env);
984928

985-
if (asyncContext.async_id == 0 && env->using_domains() &&
986-
!object_.IsEmpty()) {
987-
DomainEnter(env, object_);
988-
}
989-
990929
if (asyncContext.async_id != 0) {
991930
// No need to check a return value because the application will exit if
992931
// an exception occurs.
@@ -1016,11 +955,6 @@ void InternalCallbackScope::Close() {
1016955
AsyncWrap::EmitAfter(env_, async_context_.async_id);
1017956
}
1018957

1019-
if (async_context_.async_id == 0 && env_->using_domains() &&
1020-
!object_.IsEmpty()) {
1021-
DomainExit(env_, object_);
1022-
}
1023-
1024958
if (IsInnerMakeCallback()) {
1025959
return;
1026960
}
@@ -1061,7 +995,16 @@ MaybeLocal<Value> InternalMakeCallback(Environment* env,
1061995
return Undefined(env->isolate());
1062996
}
1063997

1064-
MaybeLocal<Value> ret = callback->Call(env->context(), recv, argc, argv);
998+
Local<Function> domain_cb = env->domain_callback();
999+
MaybeLocal<Value> ret;
1000+
if (asyncContext.async_id != 0 || domain_cb.IsEmpty() || recv.IsEmpty()) {
1001+
ret = callback->Call(env->context(), recv, argc, argv);
1002+
} else {
1003+
std::vector<Local<Value>> args(1 + argc);
1004+
args[0] = callback;
1005+
std::copy(&argv[0], &argv[argc], &args[1]);
1006+
ret = domain_cb->Call(env->context(), recv, args.size(), &args[0]);
1007+
}
10651008

10661009
if (ret.IsEmpty()) {
10671010
// NOTE: For backwards compatibility with public API we return Undefined()
@@ -3339,7 +3282,6 @@ void SetupProcessObject(Environment* env,
33393282
env->SetMethod(process, "_setupProcessObject", SetupProcessObject);
33403283
env->SetMethod(process, "_setupNextTick", SetupNextTick);
33413284
env->SetMethod(process, "_setupPromises", SetupPromises);
3342-
env->SetMethod(process, "_setupDomainUse", SetupDomainUse);
33433285
}
33443286

33453287

src/node_domain.cc

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#include "v8.h"
2+
#include "node_internals.h"
3+
4+
namespace node {
5+
namespace domain {
6+
7+
using v8::Context;
8+
using v8::Function;
9+
using v8::FunctionCallbackInfo;
10+
using v8::Local;
11+
using v8::Object;
12+
using v8::Value;
13+
14+
15+
void Enable(const FunctionCallbackInfo<Value>& args) {
16+
Environment* env = Environment::GetCurrent(args);
17+
18+
CHECK(args[0]->IsFunction());
19+
20+
env->set_domain_callback(args[0].As<Function>());
21+
}
22+
23+
void Initialize(Local<Object> target,
24+
Local<Value> unused,
25+
Local<Context> context) {
26+
Environment* env = Environment::GetCurrent(context);
27+
28+
env->SetMethod(target, "enable", Enable);
29+
}
30+
31+
} // namespace domain
32+
} // namespace node
33+
34+
NODE_MODULE_CONTEXT_AWARE_INTERNAL(domain, node::domain::Initialize)

src/node_internals.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ struct sockaddr;
104104
V(cares_wrap) \
105105
V(config) \
106106
V(contextify) \
107+
V(domain) \
107108
V(fs) \
108109
V(fs_event_wrap) \
109110
V(http2) \

test/addons/repl-domain-abort/binding.cc

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <node.h>
2323
#include <v8.h>
2424

25+
using v8::Boolean;
2526
using v8::Function;
2627
using v8::FunctionCallbackInfo;
2728
using v8::Local;
@@ -31,11 +32,16 @@ using v8::Value;
3132

3233
void Method(const FunctionCallbackInfo<Value>& args) {
3334
Isolate* isolate = args.GetIsolate();
34-
node::MakeCallback(isolate,
35-
isolate->GetCurrentContext()->Global(),
36-
args[0].As<Function>(),
37-
0,
38-
nullptr);
35+
Local<Value> params[] = {
36+
Boolean::New(isolate, true),
37+
Boolean::New(isolate, false)
38+
};
39+
Local<Value> ret = node::MakeCallback(isolate,
40+
isolate->GetCurrentContext()->Global(),
41+
args[0].As<Function>(),
42+
2,
43+
params);
44+
assert(ret->IsTrue());
3945
}
4046

4147
void init(Local<Object> exports) {

test/addons/repl-domain-abort/test.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ const lines = [
4040
// This line shouldn't cause an assertion error.
4141
`require('${buildPath}')` +
4242
// Log output to double check callback ran.
43-
'.method(function() { console.log(\'cb_ran\'); });',
43+
'.method(function(v1, v2) {' +
44+
'console.log(\'cb_ran\'); return v1 === true && v2 === false; });',
4445
];
4546

4647
const dInput = new stream.Readable();

test/cctest/node_module_reg.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
void _register_cares_wrap() {}
66
void _register_config() {}
77
void _register_contextify() {}
8+
void _register_domain() {}
89
void _register_fs() {}
910
void _register_fs_event_wrap() {}
1011
void _register_http2() {}

0 commit comments

Comments
 (0)