@@ -251,29 +251,39 @@ v8::Handle<v8::Value> Exit(const v8::Arguments& args) {
251
251
252
252
typedef void (*extInit)(Handle <Object> exports);
253
253
254
+ // DLOpen is node.dlopen(). Used to load 'module.node' dynamically shared
255
+ // objects.
254
256
Handle <Value> DLOpen (const v8::Arguments& args) {
255
257
HandleScope scope;
256
258
257
259
if (args.Length () < 2 ) return Undefined ();
258
260
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
261
263
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.
262
268
void *handle = dlopen (*filename, RTLD_LAZY);
263
269
270
+ // Handle errors.
264
271
if (handle == NULL ) {
265
272
Local<Value> exception = Exception::Error (String::New (dlerror ()));
266
273
return ThrowException (exception );
267
274
}
268
275
276
+ // Get the init() function from the dynamically shared object.
269
277
void *init_handle = dlsym (handle, " init" );
278
+ // Error out if not found.
270
279
if (init_handle == NULL ) {
271
280
Local<Value> exception =
272
281
Exception::Error (String::New (" No 'init' symbol found in module." ));
273
282
return ThrowException (exception );
274
283
}
275
- extInit init = (extInit)(init_handle);
284
+ extInit init = (extInit)(init_handle); // Cast
276
285
286
+ // Execute the C++ module
277
287
init (target);
278
288
279
289
return Undefined ();
@@ -316,14 +326,22 @@ void FatalException(TryCatch &try_catch) {
316
326
317
327
static ev_async eio_watcher;
318
328
329
+ // Called from the main thread.
319
330
static void EIOCallback (EV_P_ ev_async *watcher, int revents) {
320
331
assert (watcher == &eio_watcher);
321
332
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.
322
335
eio_poll ();
323
336
}
324
337
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.
325
340
static void EIOWantPoll (void ) {
341
+ // Signal the main thread that EIO callbacks need to be processed.
326
342
ev_async_send (EV_DEFAULT_UC_ &eio_watcher);
343
+ // EIOCallback() will be called from the main thread in the next event
344
+ // loop.
327
345
}
328
346
329
347
static ev_async debug_watcher;
@@ -337,6 +355,11 @@ static void DebugMessageCallback(EV_P_ ev_async *watcher, int revents) {
337
355
}
338
356
339
357
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.
340
363
ev_async_send (EV_DEFAULT_UC_ &debug_watcher);
341
364
}
342
365
@@ -345,6 +368,8 @@ static void ExecuteNativeJS(const char *filename, const char *data) {
345
368
HandleScope scope;
346
369
TryCatch try_catch;
347
370
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.
348
373
if (try_catch.HasCaught ()) {
349
374
puts (" There is an error in Node's built-in javascript" );
350
375
puts (" This should be reported as a bug!" );
@@ -356,90 +381,113 @@ static void ExecuteNativeJS(const char *filename, const char *data) {
356
381
static Local<Object> Load (int argc, char *argv[]) {
357
382
HandleScope scope;
358
383
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 ();
361
386
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.
363
389
390
+ // node.version
364
391
node_obj->Set (String::NewSymbol (" version" ), String::New (NODE_VERSION));
392
+ // node.installPrefix
365
393
node_obj->Set (String::NewSymbol (" installPrefix" ), String::New (NODE_PREFIX));
366
394
395
+ // process.ARGV
367
396
int i, j;
368
397
Local<Array> arguments = Array::New (argc - dash_dash_index + 1 );
369
-
370
398
arguments->Set (Integer::New (0 ), String::New (argv[0 ]));
371
399
for (j = 1 , i = dash_dash_index + 1 ; i < argc; j++, i++) {
372
400
Local<String> arg = String::New (argv[i]);
373
401
arguments->Set (Integer::New (j), arg);
374
402
}
375
- global_obj->Set (String::NewSymbol (" ARGV" ), arguments);
403
+ // assign it
404
+ process->Set (String::NewSymbol (" ARGV" ), arguments);
376
405
406
+ // create process.ENV
377
407
Local<Object> env = Object::New ();
378
408
for (i = 0 ; environ[i]; i++) {
409
+ // skip entries without a '=' character
379
410
for (j = 0 ; environ[i][j] && environ[i][j] != ' =' ; j++) { ; }
411
+ // create the v8 objects
380
412
Local<String> field = String::New (environ[i], j);
381
413
Local<String> value = Local<String>();
382
414
if (environ[i][j] == ' =' ) {
383
415
value = String::New (environ[i]+j+1 );
384
416
}
417
+ // assign them
385
418
env->Set (field, value);
386
419
}
387
- global_obj->Set (String::NewSymbol (" ENV" ), env);
420
+ // assign process.ENV
421
+ process->Set (String::NewSymbol (" ENV" ), env);
388
422
423
+ // define various internal methods
389
424
NODE_SET_METHOD (node_obj, " compile" , Compile);
390
425
NODE_SET_METHOD (node_obj, " reallyExit" , Exit);
391
426
NODE_SET_METHOD (node_obj, " cwd" , Cwd);
392
427
NODE_SET_METHOD (node_obj, " dlopen" , DLOpen);
393
428
429
+ // Assign the EventEmitter. It was created in main().
394
430
node_obj->Set (String::NewSymbol (" EventEmitter" ),
395
431
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);
404
432
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
405
441
Local<Object> dns = Object::New ();
406
442
node_obj->Set (String::NewSymbol (" dns" ), dns);
407
- DNS::Initialize (dns);
408
-
443
+ DNS::Initialize (dns); // dns.cc
409
444
Local<Object> fs = Object::New ();
410
445
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.
413
449
Local<Object> tcp = Object::New ();
414
450
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.
418
455
Local<Object> http = Object::New ();
419
456
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
422
459
460
+ // Compile, execute the src/*.js files. (Which were included a static C
461
+ // strings in node_natives.h)
423
462
ExecuteNativeJS (" util.js" , native_util);
424
463
ExecuteNativeJS (" events.js" , native_events);
425
464
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!
426
467
ExecuteNativeJS (" node.js" , native_node);
427
468
428
469
return scope.Close (node_obj);
429
470
}
430
471
431
- static void CallExitHandler () {
472
+ static void EmitExitEvent () {
432
473
HandleScope scope;
474
+
475
+ // Get reference to 'process' object.
433
476
Local<Object> process = Context::GetCurrent ()->Global ();
477
+ // Get the 'emit' function from it.
434
478
Local<Value> emit_v = process->Get (String::NewSymbol (" emit" ));
435
479
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 );
437
482
}
483
+ // Cast
438
484
Local<Function> emit = Local<Function>::Cast (emit_v);
439
485
440
486
TryCatch try_catch;
441
487
488
+ // Arguments for the emit('exit')
442
489
Local<Value> argv[2 ] = { String::New (" exit" ), Integer::New (0 ) };
490
+ // Emit!
443
491
emit->Call (process, 2 , argv);
444
492
445
493
if (try_catch.HasCaught ()) {
@@ -457,6 +505,7 @@ static void PrintHelp() {
457
505
" or with 'man node'\n " );
458
506
}
459
507
508
+ // Parse node command line arguments.
460
509
static void ParseArgs (int *argc, char **argv) {
461
510
// TODO use parse opts
462
511
for (int i = 1 ; i < *argc; i++) {
@@ -486,68 +535,111 @@ static void ParseArgs(int *argc, char **argv) {
486
535
487
536
} // namespace node
488
537
538
+
489
539
int main (int argc, char *argv[]) {
540
+ // Parse a few arguments which are specific to Node.
490
541
node::ParseArgs (&argc, argv);
542
+ // Parse the rest of the args (up to the 'dash_dash_index' (where '--' was
543
+ // in the command line))
491
544
V8::SetFlagsFromCommandLine (&node::dash_dash_index, argv, false );
492
545
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
493
554
evcom_ignore_sigpipe ();
494
- ev_default_loop (EVFLAG_AUTO); // initialize the default ev loop.
495
555
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).
497
563
ev_async_init (&node::eio_watcher, node::EIOCallback);
564
+ // 2. Actaully start the thread pool.
498
565
eio_init (node::EIOWantPoll, NULL );
566
+ // 3. Start watcher.
499
567
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.
500
570
ev_unref (EV_DEFAULT_UC);
501
571
502
572
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
-
511
573
HandleScope handle_scope;
512
574
575
+ V8::SetFatalErrorHandler (node::OnFatalError);
576
+
513
577
#define AUTO_BREAK_FLAG " --debugger_auto_break"
578
+ // If the --debug flag was specified then initialize the debug thread.
514
579
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
515
582
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.
516
588
ev_async_init (&node::debug_watcher, node::DebugMessageCallback);
589
+ // Set the callback DebugMessageDispatch which is called from the debug
590
+ // thread.
517
591
Debug::SetDebugMessageDispatchHandler (node::DebugMessageDispatch);
592
+ // Start the async watcher.
518
593
ev_async_start (EV_DEFAULT_UC_ &node::debug_watcher);
594
+ // unref it so that we exit the event loop despite it being active.
519
595
ev_unref (EV_DEFAULT_UC);
520
596
597
+ // Start the debug thread and it's associated TCP server on port 5858.
521
598
bool r = Debug::EnableAgent (" node " NODE_VERSION, 5858 );
599
+ // Crappy check that everything went well. FIXME
522
600
assert (r);
601
+ // Print out some information. REMOVEME
523
602
printf (" debugger listening on port 5858\n "
524
603
" Use 'd8 --remote_debugger' to access it.\n " );
525
604
}
526
605
606
+ // Create the global 'process' object's FunctionTemplate.
527
607
Local<FunctionTemplate> process_template = FunctionTemplate::New ();
528
608
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.
532
613
node::EventEmitter::Initialize (process_template);
533
614
615
+ // Create the one and only Context.
534
616
Persistent<Context> context = Context::New (NULL ,
535
617
process_template->InstanceTemplate ());
536
618
Context::Scope context_scope (context);
537
619
538
-
539
-
620
+ // Actually assign the global object to it's place as 'process'
540
621
context->Global ()->Set (String::NewSymbol (" process" ), context->Global ());
541
622
623
+ // Create all the objects, load modules, do everything.
624
+ // so your next reading stop should be node::Load()!
542
625
Local<Object> node_obj = node::Load (argc, argv);
543
626
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.
544
632
ev_loop (EV_DEFAULT_UC_ 0 ); // main event loop
545
633
546
- node::CallExitHandler ();
634
+ // Once we've dropped out, emit the 'exit' event from 'process'
635
+ node::EmitExitEvent ();
547
636
637
+ #ifndef NDEBUG
638
+ printf (" clean up\n " );
639
+ // Clean up.
548
640
context.Dispose ();
549
641
V8::Dispose ();
550
-
642
+ # endif // NDEBUG
551
643
return 0 ;
552
644
}
553
645
0 commit comments