Skip to content
Prev Previous commit
Next Next commit
process: move C++ process events into node_process_events.cc
Move the C++ `process.emit` and `process.emitWarning` methods
from `node.cc` into into `node_process_events.cc`, and
reuse the implementation in other places that need to do
`process.emit` in C++.
  • Loading branch information
joyeecheung committed Jan 9, 2019
commit 5e1b8a27eb3f9d20405b098f3f2a0f4bcfdee3ee
1 change: 1 addition & 0 deletions node.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,7 @@
'src/node_perf.cc',
'src/node_platform.cc',
'src/node_postmortem_metadata.cc',
'src/node_process_events.cc',
'src/node_process_methods.cc',
'src/node_process_object.cc',
'src/node_serdes.cc',
Expand Down
17 changes: 2 additions & 15 deletions src/inspector_agent.cc
Original file line number Diff line number Diff line change
Expand Up @@ -370,26 +370,13 @@ class SameThreadInspectorSession : public InspectorSession {
void NotifyClusterWorkersDebugEnabled(Environment* env) {
Isolate* isolate = env->isolate();
HandleScope handle_scope(isolate);
auto context = env->context();
Local<Context> context = env->context();

// Send message to enable debug in cluster workers
Local<Object> process_object = env->process_object();
Local<Value> emit_fn =
process_object->Get(context, FIXED_ONE_BYTE_STRING(isolate, "emit"))
.ToLocalChecked();
// In case the thread started early during the startup
if (!emit_fn->IsFunction())
return;

Local<Object> message = Object::New(isolate);
message->Set(context, FIXED_ONE_BYTE_STRING(isolate, "cmd"),
FIXED_ONE_BYTE_STRING(isolate, "NODE_DEBUG_ENABLED")).FromJust();
Local<Value> argv[] = {
FIXED_ONE_BYTE_STRING(isolate, "internalMessage"),
message
};
MakeCallback(env->isolate(), process_object, emit_fn.As<Function>(),
arraysize(argv), argv, {0, 0});
ProcessEmit(env, "internalMessage", message);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sounds like something we might want to migrate off process.emit(), right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@addaleax yeah, this looks like the only place where internalMessage is emitted, maybe the C++ side can call a method passed from JS side somehow instead ..

}

#ifdef _WIN32
Expand Down
104 changes: 7 additions & 97 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@ using v8::MaybeLocal;
using v8::Message;
using v8::MicrotasksPolicy;
using v8::NewStringType;
using v8::Nothing;
using v8::Object;
using v8::ObjectTemplate;
using v8::Script;
Expand Down Expand Up @@ -582,82 +581,6 @@ void Exit(const FunctionCallbackInfo<Value>& args) {
env->Exit(code);
}

static Maybe<bool> ProcessEmitWarningGeneric(Environment* env,
const char* warning,
const char* type = nullptr,
const char* code = nullptr) {
HandleScope handle_scope(env->isolate());
Context::Scope context_scope(env->context());

Local<Object> process = env->process_object();
Local<Value> emit_warning;
if (!process->Get(env->context(),
env->emit_warning_string()).ToLocal(&emit_warning)) {
return Nothing<bool>();
}

if (!emit_warning->IsFunction()) return Just(false);

int argc = 0;
Local<Value> args[3]; // warning, type, code

// The caller has to be able to handle a failure anyway, so we might as well
// do proper error checking for string creation.
if (!String::NewFromUtf8(env->isolate(),
warning,
NewStringType::kNormal).ToLocal(&args[argc++])) {
return Nothing<bool>();
}
if (type != nullptr) {
if (!String::NewFromOneByte(env->isolate(),
reinterpret_cast<const uint8_t*>(type),
NewStringType::kNormal)
.ToLocal(&args[argc++])) {
return Nothing<bool>();
}
if (code != nullptr &&
!String::NewFromOneByte(env->isolate(),
reinterpret_cast<const uint8_t*>(code),
NewStringType::kNormal)
.ToLocal(&args[argc++])) {
return Nothing<bool>();
}
}

// MakeCallback() unneeded because emitWarning is internal code, it calls
// process.emit('warning', ...), but does so on the nextTick.
if (emit_warning.As<Function>()->Call(env->context(),
process,
argc,
args).IsEmpty()) {
return Nothing<bool>();
}
return Just(true);
}


// Call process.emitWarning(str), fmt is a snprintf() format string
Maybe<bool> ProcessEmitWarning(Environment* env, const char* fmt, ...) {
char warning[1024];
va_list ap;

va_start(ap, fmt);
vsnprintf(warning, sizeof(warning), fmt, ap);
va_end(ap);

return ProcessEmitWarningGeneric(env, warning);
}


Maybe<bool> ProcessEmitDeprecationWarning(Environment* env,
const char* warning,
const char* deprecation_code) {
return ProcessEmitWarningGeneric(env,
warning,
"DeprecationWarning",
deprecation_code);
}

static void OnMessage(Local<Message> message, Local<Value> error) {
Isolate* isolate = message->GetIsolate();
switch (message->ErrorLevel()) {
Expand Down Expand Up @@ -1163,19 +1086,14 @@ void RunBeforeExit(Environment* env) {
void EmitBeforeExit(Environment* env) {
HandleScope handle_scope(env->isolate());
Context::Scope context_scope(env->context());
Local<Object> process_object = env->process_object();
Local<String> exit_code = env->exit_code_string();
Local<Value> args[] = {
FIXED_ONE_BYTE_STRING(env->isolate(), "beforeExit"),
process_object->Get(env->context(), exit_code).ToLocalChecked()
->ToInteger(env->context()).ToLocalChecked()
};
MakeCallback(env->isolate(),
process_object, "emit", arraysize(args), args,
{0, 0}).ToLocalChecked();
Local<Value> exit_code = env->process_object()
->Get(env->context(), env->exit_code_string())
.ToLocalChecked()
->ToInteger(env->context())
.ToLocalChecked();
ProcessEmit(env, "beforeExit", exit_code).ToLocalChecked();
}


int EmitExit(Environment* env) {
// process.emit('exit')
HandleScope handle_scope(env->isolate());
Expand All @@ -1188,15 +1106,7 @@ int EmitExit(Environment* env) {
Local<String> exit_code = env->exit_code_string();
int code = process_object->Get(env->context(), exit_code).ToLocalChecked()
->Int32Value(env->context()).ToChecked();

Local<Value> args[] = {
FIXED_ONE_BYTE_STRING(env->isolate(), "exit"),
Integer::New(env->isolate(), code)
};

MakeCallback(env->isolate(),
process_object, "emit", arraysize(args), args,
{0, 0}).ToLocalChecked();
ProcessEmit(env, "exit", Integer::New(env->isolate(), code));

// Reload exit code, it may be changed by `emit('exit')`
return process_object->Get(env->context(), exit_code).ToLocalChecked()
Expand Down
9 changes: 9 additions & 0 deletions src/node_process.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ v8::Local<v8::Object> CreateEnvVarProxy(v8::Local<v8::Context> context,
// function, it is useful to bypass JavaScript entirely.
void RawDebug(const v8::FunctionCallbackInfo<v8::Value>& args);

v8::MaybeLocal<v8::Value> ProcessEmit(Environment* env,
const char* event,
v8::Local<v8::Value> message);

v8::Maybe<bool> ProcessEmitWarningGeneric(Environment* env,
const char* warning,
const char* type = nullptr,
const char* code = nullptr);

v8::Maybe<bool> ProcessEmitWarning(Environment* env, const char* fmt, ...);
v8::Maybe<bool> ProcessEmitDeprecationWarning(Environment* env,
const char* warning,
Expand Down
103 changes: 103 additions & 0 deletions src/node_process_events.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
#include <stdarg.h>

#include "env.h"
#include "node_internals.h"
#include "node_process.h"

namespace node {
using v8::Context;
using v8::Function;
using v8::HandleScope;
using v8::Isolate;
using v8::Just;
using v8::Local;
using v8::Maybe;
using v8::MaybeLocal;
using v8::NewStringType;
using v8::Nothing;
using v8::Object;
using v8::String;
using v8::Value;

MaybeLocal<Value> ProcessEmit(Environment* env,
const char* event,
Local<Value> message) {
// Send message to enable debug in cluster workers
Local<Object> process = env->process_object();
Isolate* isolate = env->isolate();
Local<Value> argv[] = {OneByteString(isolate, event), message};

return MakeCallback(isolate, process, "emit", arraysize(argv), argv, {0, 0});
}

Maybe<bool> ProcessEmitWarningGeneric(Environment* env,
const char* warning,
const char* type,
const char* code) {
HandleScope handle_scope(env->isolate());
Context::Scope context_scope(env->context());

Local<Object> process = env->process_object();
Local<Value> emit_warning;
if (!process->Get(env->context(), env->emit_warning_string())
.ToLocal(&emit_warning)) {
return Nothing<bool>();
}

if (!emit_warning->IsFunction()) return Just(false);

int argc = 0;
Local<Value> args[3]; // warning, type, code

// The caller has to be able to handle a failure anyway, so we might as well
// do proper error checking for string creation.
if (!String::NewFromUtf8(env->isolate(), warning, NewStringType::kNormal)
.ToLocal(&args[argc++])) {
return Nothing<bool>();
}
if (type != nullptr) {
if (!String::NewFromOneByte(env->isolate(),
reinterpret_cast<const uint8_t*>(type),
NewStringType::kNormal)
.ToLocal(&args[argc++])) {
return Nothing<bool>();
}
if (code != nullptr &&
!String::NewFromOneByte(env->isolate(),
reinterpret_cast<const uint8_t*>(code),
NewStringType::kNormal)
.ToLocal(&args[argc++])) {
return Nothing<bool>();
}
}

// MakeCallback() unneeded because emitWarning is internal code, it calls
// process.emit('warning', ...), but does so on the nextTick.
if (emit_warning.As<Function>()
->Call(env->context(), process, argc, args)
.IsEmpty()) {
return Nothing<bool>();
}
return Just(true);
}

// Call process.emitWarning(str), fmt is a snprintf() format string
Maybe<bool> ProcessEmitWarning(Environment* env, const char* fmt, ...) {
char warning[1024];
va_list ap;

va_start(ap, fmt);
vsnprintf(warning, sizeof(warning), fmt, ap);
va_end(ap);

return ProcessEmitWarningGeneric(env, warning);
}

Maybe<bool> ProcessEmitDeprecationWarning(Environment* env,
const char* warning,
const char* deprecation_code) {
return ProcessEmitWarningGeneric(
env, warning, "DeprecationWarning", deprecation_code);
}

} // namespace node