Skip to content

Commit 3881455

Browse files
committed
Add comments to node.cc
1 parent 962e929 commit 3881455

File tree

1 file changed

+137
-45
lines changed

1 file changed

+137
-45
lines changed

src/node.cc

+137-45
Original file line numberDiff line numberDiff line change
@@ -251,29 +251,39 @@ v8::Handle<v8::Value> Exit(const v8::Arguments& args) {
251251

252252
typedef void (*extInit)(Handle<Object> exports);
253253

254+
// DLOpen is node.dlopen(). Used to load 'module.node' dynamically shared
255+
// objects.
254256
Handle<Value> DLOpen(const v8::Arguments& args) {
255257
HandleScope scope;
256258

257259
if (args.Length() < 2) return Undefined();
258260

259-
String::Utf8Value filename(args[0]->ToString());
260-
Local<Object> target = args[1]->ToObject();
261+
String::Utf8Value filename(args[0]->ToString()); // Cast
262+
Local<Object> target = args[1]->ToObject(); // Cast
261263

264+
// Actually call dlopen().
265+
// FIXME: This is a blocking function and should be called asynchronously!
266+
// This function should be moved to file.cc and use libeio to make this
267+
// system call.
262268
void *handle = dlopen(*filename, RTLD_LAZY);
263269

270+
// Handle errors.
264271
if (handle == NULL) {
265272
Local<Value> exception = Exception::Error(String::New(dlerror()));
266273
return ThrowException(exception);
267274
}
268275

276+
// Get the init() function from the dynamically shared object.
269277
void *init_handle = dlsym(handle, "init");
278+
// Error out if not found.
270279
if (init_handle == NULL) {
271280
Local<Value> exception =
272281
Exception::Error(String::New("No 'init' symbol found in module."));
273282
return ThrowException(exception);
274283
}
275-
extInit init = (extInit)(init_handle);
284+
extInit init = (extInit)(init_handle); // Cast
276285

286+
// Execute the C++ module
277287
init(target);
278288

279289
return Undefined();
@@ -316,14 +326,22 @@ void FatalException(TryCatch &try_catch) {
316326

317327
static ev_async eio_watcher;
318328

329+
// Called from the main thread.
319330
static void EIOCallback(EV_P_ ev_async *watcher, int revents) {
320331
assert(watcher == &eio_watcher);
321332
assert(revents == EV_ASYNC);
333+
// Give control to EIO to process responses. In nearly every case
334+
// EIOPromise::After() (file.cc) is called once EIO receives the response.
322335
eio_poll();
323336
}
324337

338+
// EIOWantPoll() is called from the EIO thread pool each time an EIO
339+
// request (that is, one of the node.fs.* functions) has completed.
325340
static void EIOWantPoll(void) {
341+
// Signal the main thread that EIO callbacks need to be processed.
326342
ev_async_send(EV_DEFAULT_UC_ &eio_watcher);
343+
// EIOCallback() will be called from the main thread in the next event
344+
// loop.
327345
}
328346

329347
static ev_async debug_watcher;
@@ -337,6 +355,11 @@ static void DebugMessageCallback(EV_P_ ev_async *watcher, int revents) {
337355
}
338356

339357
static void DebugMessageDispatch(void) {
358+
// This function is called from V8's debug thread when a debug TCP client
359+
// has sent a message.
360+
361+
// Send a signal to our main thread saying that it should enter V8 to
362+
// handle the message.
340363
ev_async_send(EV_DEFAULT_UC_ &debug_watcher);
341364
}
342365

@@ -345,6 +368,8 @@ static void ExecuteNativeJS(const char *filename, const char *data) {
345368
HandleScope scope;
346369
TryCatch try_catch;
347370
ExecuteString(String::New(data), String::New(filename));
371+
// There should not be any syntax errors in these file!
372+
// If there are exit the process.
348373
if (try_catch.HasCaught()) {
349374
puts("There is an error in Node's built-in javascript");
350375
puts("This should be reported as a bug!");
@@ -356,90 +381,113 @@ static void ExecuteNativeJS(const char *filename, const char *data) {
356381
static Local<Object> Load(int argc, char *argv[]) {
357382
HandleScope scope;
358383

359-
Local<Object> global_obj = Context::GetCurrent()->Global();
360-
Local<Object> node_obj = Object::New();
384+
// Reference to 'process'
385+
Local<Object> process = Context::GetCurrent()->Global();
361386

362-
global_obj->Set(String::NewSymbol("node"), node_obj);
387+
Local<Object> node_obj = Object::New(); // Create the 'process.node' object
388+
process->Set(String::NewSymbol("node"), node_obj); // and assign it.
363389

390+
// node.version
364391
node_obj->Set(String::NewSymbol("version"), String::New(NODE_VERSION));
392+
// node.installPrefix
365393
node_obj->Set(String::NewSymbol("installPrefix"), String::New(NODE_PREFIX));
366394

395+
// process.ARGV
367396
int i, j;
368397
Local<Array> arguments = Array::New(argc - dash_dash_index + 1);
369-
370398
arguments->Set(Integer::New(0), String::New(argv[0]));
371399
for (j = 1, i = dash_dash_index + 1; i < argc; j++, i++) {
372400
Local<String> arg = String::New(argv[i]);
373401
arguments->Set(Integer::New(j), arg);
374402
}
375-
global_obj->Set(String::NewSymbol("ARGV"), arguments);
403+
// assign it
404+
process->Set(String::NewSymbol("ARGV"), arguments);
376405

406+
// create process.ENV
377407
Local<Object> env = Object::New();
378408
for (i = 0; environ[i]; i++) {
409+
// skip entries without a '=' character
379410
for (j = 0; environ[i][j] && environ[i][j] != '='; j++) { ; }
411+
// create the v8 objects
380412
Local<String> field = String::New(environ[i], j);
381413
Local<String> value = Local<String>();
382414
if (environ[i][j] == '=') {
383415
value = String::New(environ[i]+j+1);
384416
}
417+
// assign them
385418
env->Set(field, value);
386419
}
387-
global_obj->Set(String::NewSymbol("ENV"), env);
420+
// assign process.ENV
421+
process->Set(String::NewSymbol("ENV"), env);
388422

423+
// define various internal methods
389424
NODE_SET_METHOD(node_obj, "compile", Compile);
390425
NODE_SET_METHOD(node_obj, "reallyExit", Exit);
391426
NODE_SET_METHOD(node_obj, "cwd", Cwd);
392427
NODE_SET_METHOD(node_obj, "dlopen", DLOpen);
393428

429+
// Assign the EventEmitter. It was created in main().
394430
node_obj->Set(String::NewSymbol("EventEmitter"),
395431
EventEmitter::constructor_template->GetFunction());
396-
Promise::Initialize(node_obj);
397-
398-
Stdio::Initialize(node_obj);
399-
Timer::Initialize(node_obj);
400-
SignalHandler::Initialize(node_obj);
401-
ChildProcess::Initialize(node_obj);
402-
403-
DefineConstants(node_obj);
404432

433+
// Initialize the C++ modules..................filename of module
434+
Promise::Initialize(node_obj); // events.cc
435+
Stdio::Initialize(node_obj); // stdio.cc
436+
Timer::Initialize(node_obj); // timer.cc
437+
SignalHandler::Initialize(node_obj); // signal_handler.cc
438+
ChildProcess::Initialize(node_obj); // child_process.cc
439+
DefineConstants(node_obj); // constants.cc
440+
// Create node.dns
405441
Local<Object> dns = Object::New();
406442
node_obj->Set(String::NewSymbol("dns"), dns);
407-
DNS::Initialize(dns);
408-
443+
DNS::Initialize(dns); // dns.cc
409444
Local<Object> fs = Object::New();
410445
node_obj->Set(String::NewSymbol("fs"), fs);
411-
File::Initialize(fs);
412-
446+
File::Initialize(fs); // file.cc
447+
// Create node.tcp. Note this separate from lib/tcp.js which is the public
448+
// frontend.
413449
Local<Object> tcp = Object::New();
414450
node_obj->Set(String::New("tcp"), tcp);
415-
Server::Initialize(tcp);
416-
Connection::Initialize(tcp);
417-
451+
Server::Initialize(tcp); // tcp.cc
452+
Connection::Initialize(tcp); // tcp.cc
453+
// Create node.http. Note this separate from lib/http.js which is the
454+
// public frontend.
418455
Local<Object> http = Object::New();
419456
node_obj->Set(String::New("http"), http);
420-
HTTPServer::Initialize(http);
421-
HTTPConnection::Initialize(http);
457+
HTTPServer::Initialize(http); // http.cc
458+
HTTPConnection::Initialize(http); // http.cc
422459

460+
// Compile, execute the src/*.js files. (Which were included a static C
461+
// strings in node_natives.h)
423462
ExecuteNativeJS("util.js", native_util);
424463
ExecuteNativeJS("events.js", native_events);
425464
ExecuteNativeJS("file.js", native_file);
465+
// In node.js we actually load the file specified in ARGV[1]
466+
// so your next reading stop should be node.js!
426467
ExecuteNativeJS("node.js", native_node);
427468

428469
return scope.Close(node_obj);
429470
}
430471

431-
static void CallExitHandler() {
472+
static void EmitExitEvent() {
432473
HandleScope scope;
474+
475+
// Get reference to 'process' object.
433476
Local<Object> process = Context::GetCurrent()->Global();
477+
// Get the 'emit' function from it.
434478
Local<Value> emit_v = process->Get(String::NewSymbol("emit"));
435479
if (!emit_v->IsFunction()) {
436-
exit(10); // could not emit exit event so exit with error code 10.
480+
// could not emit exit event so exit
481+
exit(10);
437482
}
483+
// Cast
438484
Local<Function> emit = Local<Function>::Cast(emit_v);
439485

440486
TryCatch try_catch;
441487

488+
// Arguments for the emit('exit')
442489
Local<Value> argv[2] = { String::New("exit"), Integer::New(0) };
490+
// Emit!
443491
emit->Call(process, 2, argv);
444492

445493
if (try_catch.HasCaught()) {
@@ -457,6 +505,7 @@ static void PrintHelp() {
457505
" or with 'man node'\n");
458506
}
459507

508+
// Parse node command line arguments.
460509
static void ParseArgs(int *argc, char **argv) {
461510
// TODO use parse opts
462511
for (int i = 1; i < *argc; i++) {
@@ -486,68 +535,111 @@ static void ParseArgs(int *argc, char **argv) {
486535

487536
} // namespace node
488537

538+
489539
int main(int argc, char *argv[]) {
540+
// Parse a few arguments which are specific to Node.
490541
node::ParseArgs(&argc, argv);
542+
// Parse the rest of the args (up to the 'dash_dash_index' (where '--' was
543+
// in the command line))
491544
V8::SetFlagsFromCommandLine(&node::dash_dash_index, argv, false);
492545

546+
// Error out if we don't have a script argument.
547+
if (argc < 2) {
548+
fprintf(stderr, "No script was specified.\n");
549+
node::PrintHelp();
550+
return 1;
551+
}
552+
553+
// Ignore the SIGPIPE
493554
evcom_ignore_sigpipe();
494-
ev_default_loop(EVFLAG_AUTO); // initialize the default ev loop.
495555

496-
// start eio thread pool
556+
// Initialize the default ev loop.
557+
ev_default_loop(EVFLAG_AUTO);
558+
559+
// Start the EIO thread pool:
560+
// 1. Initialize the ev_async watcher which allows for notification from
561+
// the thread pool (in node::EIOWantPoll) to poll for updates (in
562+
// node::EIOCallback).
497563
ev_async_init(&node::eio_watcher, node::EIOCallback);
564+
// 2. Actaully start the thread pool.
498565
eio_init(node::EIOWantPoll, NULL);
566+
// 3. Start watcher.
499567
ev_async_start(EV_DEFAULT_UC_ &node::eio_watcher);
568+
// 4. Remove a reference to the async watcher. This means we'll drop out
569+
// of the ev_loop even though eio_watcher is active.
500570
ev_unref(EV_DEFAULT_UC);
501571

502572
V8::Initialize();
503-
V8::SetFatalErrorHandler(node::OnFatalError);
504-
505-
if (argc < 2) {
506-
fprintf(stderr, "No script was specified.\n");
507-
node::PrintHelp();
508-
return 1;
509-
}
510-
511573
HandleScope handle_scope;
512574

575+
V8::SetFatalErrorHandler(node::OnFatalError);
576+
513577
#define AUTO_BREAK_FLAG "--debugger_auto_break"
578+
// If the --debug flag was specified then initialize the debug thread.
514579
if (node::use_debug_agent) {
580+
// First apply --debugger_auto_break setting to V8. This is so we can
581+
// enter V8 by just executing any bit of javascript
515582
V8::SetFlagsFromString(AUTO_BREAK_FLAG, sizeof(AUTO_BREAK_FLAG));
583+
// Initialize the async watcher for receiving messages from the debug
584+
// thread and marshal it into the main thread. DebugMessageCallback()
585+
// is called from the main thread to execute a random bit of javascript
586+
// - which will give V8 control so it can handle whatever new message
587+
// had been received on the debug thread.
516588
ev_async_init(&node::debug_watcher, node::DebugMessageCallback);
589+
// Set the callback DebugMessageDispatch which is called from the debug
590+
// thread.
517591
Debug::SetDebugMessageDispatchHandler(node::DebugMessageDispatch);
592+
// Start the async watcher.
518593
ev_async_start(EV_DEFAULT_UC_ &node::debug_watcher);
594+
// unref it so that we exit the event loop despite it being active.
519595
ev_unref(EV_DEFAULT_UC);
520596

597+
// Start the debug thread and it's associated TCP server on port 5858.
521598
bool r = Debug::EnableAgent("node " NODE_VERSION, 5858);
599+
// Crappy check that everything went well. FIXME
522600
assert(r);
601+
// Print out some information. REMOVEME
523602
printf("debugger listening on port 5858\n"
524603
"Use 'd8 --remote_debugger' to access it.\n");
525604
}
526605

606+
// Create the global 'process' object's FunctionTemplate.
527607
Local<FunctionTemplate> process_template = FunctionTemplate::New();
528608

529-
// The global object / "process" is an instance of EventEmitter. For
530-
// strange reasons we must initialize EventEmitter now! it will be assign
531-
// to it's namespace node.EventEmitter in Load() bellow.
609+
// The global object (process) is an instance of EventEmitter. For some
610+
// strange and forgotten reasons we must initialize EventEmitter now
611+
// before creating the Context. EventEmitter will be assigned to it's
612+
// namespace node.EventEmitter in Load() bellow.
532613
node::EventEmitter::Initialize(process_template);
533614

615+
// Create the one and only Context.
534616
Persistent<Context> context = Context::New(NULL,
535617
process_template->InstanceTemplate());
536618
Context::Scope context_scope(context);
537619

538-
539-
620+
// Actually assign the global object to it's place as 'process'
540621
context->Global()->Set(String::NewSymbol("process"), context->Global());
541622

623+
// Create all the objects, load modules, do everything.
624+
// so your next reading stop should be node::Load()!
542625
Local<Object> node_obj = node::Load(argc, argv);
543626

627+
// All our arguments are loaded. We've evaluated all of the scripts. We
628+
// might even have created TCP servers. Now we enter the main event loop.
629+
// If there are no watchers on the loop (except for the ones that were
630+
// ev_unref'd) then this function exits. As long as there are active
631+
// watchers, it blocks.
544632
ev_loop(EV_DEFAULT_UC_ 0); // main event loop
545633

546-
node::CallExitHandler();
634+
// Once we've dropped out, emit the 'exit' event from 'process'
635+
node::EmitExitEvent();
547636

637+
#ifndef NDEBUG
638+
printf("clean up\n");
639+
// Clean up.
548640
context.Dispose();
549641
V8::Dispose();
550-
642+
#endif // NDEBUG
551643
return 0;
552644
}
553645

0 commit comments

Comments
 (0)