Skip to content

Commit

Permalink
node: count callouts to JS to reemit beforeExit
Browse files Browse the repository at this point in the history
  • Loading branch information
indutny committed Oct 15, 2015
1 parent 5d7262c commit c3df7da
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 10 deletions.
1 change: 1 addition & 0 deletions src/async-wrap-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ inline AsyncWrap::AsyncWrap(Environment* env,
v8::TryCatch try_catch;

v8::Local<v8::Value> n = v8::Int32::New(env->isolate(), provider);
env->inc_callout_count();
env->async_hooks_init_function()->Call(object, 1, &n);

if (try_catch.HasCaught())
Expand Down
6 changes: 6 additions & 0 deletions src/async-wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ Local<Value> AsyncWrap::MakeCallback(const Local<Function> cb,
if (has_domain) {
Local<Value> enter_v = domain->Get(env()->enter_string());
if (enter_v->IsFunction()) {
env()->inc_callout_count();

This comment has been minimized.

Copy link
@trevnorris

trevnorris Oct 15, 2015

The only one that would be needed is for the callback call. You only check if a call has been made, and MakeCallback can't have been called w/o passing a Function.

enter_v.As<Function>()->Call(domain, 0, nullptr);
if (try_catch.HasCaught())
return Undefined(env()->isolate());
Expand All @@ -193,12 +194,14 @@ Local<Value> AsyncWrap::MakeCallback(const Local<Function> cb,

if (has_async_queue()) {
try_catch.SetVerbose(false);
env()->inc_callout_count();
env()->async_hooks_pre_function()->Call(context, 0, nullptr);
if (try_catch.HasCaught())
FatalError("node::AsyncWrap::MakeCallback", "pre hook threw");
try_catch.SetVerbose(true);
}

env()->inc_callout_count();
Local<Value> ret = cb->Call(context, argc, argv);

if (try_catch.HasCaught()) {
Expand All @@ -207,6 +210,7 @@ Local<Value> AsyncWrap::MakeCallback(const Local<Function> cb,

if (has_async_queue()) {
try_catch.SetVerbose(false);
env()->inc_callout_count();
env()->async_hooks_post_function()->Call(context, 0, nullptr);
if (try_catch.HasCaught())
FatalError("node::AsyncWrap::MakeCallback", "post hook threw");
Expand All @@ -216,6 +220,7 @@ Local<Value> AsyncWrap::MakeCallback(const Local<Function> cb,
if (has_domain) {
Local<Value> exit_v = domain->Get(env()->exit_string());
if (exit_v->IsFunction()) {
env()->inc_callout_count();
exit_v.As<Function>()->Call(domain, 0, nullptr);
if (try_catch.HasCaught())
return Undefined(env()->isolate());
Expand All @@ -239,6 +244,7 @@ Local<Value> AsyncWrap::MakeCallback(const Local<Function> cb,

tick_info->set_in_tick(true);

env()->inc_callout_count();
env()->tick_callback_function()->Call(process, 0, nullptr);

tick_info->set_in_tick(false);
Expand Down
15 changes: 15 additions & 0 deletions src/env-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,21 @@ inline void Environment::set_http_parser_buffer(char* buffer) {
http_parser_buffer_ = buffer;
}


inline unsigned int Environment::callout_count() const {
return callout_count_;
}


inline void Environment::reset_callout_count() {
callout_count_ = 0;
}


inline void Environment::inc_callout_count() {
callout_count_++;
}

This comment has been minimized.

Copy link
@indutny

indutny Oct 15, 2015

Author Owner

Argh, style.

inline Environment* Environment::from_cares_timer_handle(uv_timer_t* handle) {
return ContainerOf(&Environment::cares_timer_handle_, handle);
}
Expand Down
5 changes: 5 additions & 0 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,10 @@ class Environment {
inline char* http_parser_buffer() const;
inline void set_http_parser_buffer(char* buffer);

inline unsigned int callout_count() const;
inline void reset_callout_count();
inline void inc_callout_count();

inline void ThrowError(const char* errmsg);
inline void ThrowTypeError(const char* errmsg);
inline void ThrowRangeError(const char* errmsg);
Expand Down Expand Up @@ -551,6 +555,7 @@ class Environment {
uint32_t* heap_statistics_buffer_ = nullptr;

char* http_parser_buffer_;
unsigned int callout_count_ = 0;

#define V(PropertyName, TypeName) \
v8::Persistent<TypeName> PropertyName ## _;
Expand Down
20 changes: 10 additions & 10 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1015,6 +1015,7 @@ void PromiseRejectCallback(PromiseRejectMessage message) {
Local<Value> args[] = { event, promise, value };
Local<Object> process = env->process_object();

env->inc_callout_count();
callback->Call(process, ARRAY_SIZE(args), args);
}

Expand Down Expand Up @@ -1068,24 +1069,28 @@ Local<Value> MakeCallback(Environment* env,
if (has_domain) {
Local<Value> enter_v = domain->Get(env->enter_string());
if (enter_v->IsFunction()) {
enter_v.As<Function>()->Call(domain, 0, nullptr);
env->inc_callout_count();
enter_v.As<Function>()->Call(domain, 0, nullptr);
if (try_catch.HasCaught())
return Undefined(env->isolate());
}
}

if (has_async_queue) {
try_catch.SetVerbose(false);
env->inc_callout_count();
env->async_hooks_pre_function()->Call(object, 0, nullptr);
if (try_catch.HasCaught())
FatalError("node::MakeCallback", "pre hook threw");
try_catch.SetVerbose(true);
}

env->inc_callout_count();
Local<Value> ret = callback->Call(recv, argc, argv);

if (has_async_queue) {
try_catch.SetVerbose(false);
env->inc_callout_count();
env->async_hooks_post_function()->Call(object, 0, nullptr);
if (try_catch.HasCaught())
FatalError("node::MakeCallback", "post hook threw");
Expand All @@ -1095,6 +1100,7 @@ Local<Value> MakeCallback(Environment* env,
if (has_domain) {
Local<Value> exit_v = domain->Get(env->exit_string());
if (exit_v->IsFunction()) {
env->inc_callout_count();
exit_v.As<Function>()->Call(domain, 0, nullptr);
if (try_catch.HasCaught())
return Undefined(env->isolate());
Expand Down Expand Up @@ -3971,17 +3977,11 @@ static void StartNodeInstance(void* arg) {
v8::platform::PumpMessageLoop(default_platform, isolate);
EmitBeforeExit(env);

// If there are only unrefed handles left, we need to run an
// extra event loop turn to purge the unrefed handles.
if (event_loop->active_handles == 0 &&
event_loop->handle_queue[0] != event_loop->handle_queue[1])
uv_run(event_loop, UV_RUN_NOWAIT);

// Emit `beforeExit` if the loop became alive either after emitting
// event, or after running some callbacks.
more = uv_loop_alive(event_loop);
if (uv_run(event_loop, UV_RUN_NOWAIT) != 0)
more = true;
env->reset_callout_count();
uv_run(event_loop, UV_RUN_NOWAIT);
more = uv_loop_alive(event_loop) || env->callout_count() != 0;
}
} while (more == true);
}
Expand Down

0 comments on commit c3df7da

Please sign in to comment.