1c0fc8b59c9fd3e92d87e147033fc3cc06d99820
[platform/upstream/nodejs.git] / src / node.js
1 // Copyright Joyent, Inc. and other Node contributors.
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to permit
8 // persons to whom the Software is furnished to do so, subject to the
9 // following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 // Hello, and welcome to hacking node.js!
23 //
24 // This file is invoked by node::Load in src/node.cc, and responsible for
25 // bootstrapping the node.js core. Special caution is given to the performance
26 // of the startup process, so many dependencies are invoked lazily.
27 (function(process) {
28   this.global = this;
29   var _errorHandler;
30
31   function startup() {
32     var EventEmitter = NativeModule.require('events').EventEmitter;
33
34     process.__proto__ = Object.create(EventEmitter.prototype, {
35       constructor: {
36         value: process.constructor
37       }
38     });
39     EventEmitter.call(process);
40
41     process.EventEmitter = EventEmitter; // process.EventEmitter is deprecated
42
43     // do this good and early, since it handles errors.
44     startup.processFatal();
45
46     startup.globalVariables();
47     startup.globalTimeouts();
48     startup.globalConsole();
49
50     startup.processAsyncListener();
51     startup.processAssert();
52     startup.processConfig();
53     startup.processNextTick();
54     startup.processStdio();
55     startup.processKillAndExit();
56     startup.processSignalHandlers();
57
58     startup.processChannel();
59
60     startup.processRawDebug();
61
62     startup.resolveArgv0();
63
64     // There are various modes that Node can run in. The most common two
65     // are running from a script and running the REPL - but there are a few
66     // others like the debugger or running --eval arguments. Here we decide
67     // which mode we run in.
68
69     if (NativeModule.exists('_third_party_main')) {
70       // To allow people to extend Node in different ways, this hook allows
71       // one to drop a file lib/_third_party_main.js into the build
72       // directory which will be executed instead of Node's normal loading.
73       process.nextTick(function() {
74         NativeModule.require('_third_party_main');
75       });
76
77     } else if (process.argv[1] == 'debug') {
78       // Start the debugger agent
79       var d = NativeModule.require('_debugger');
80       d.start();
81
82     } else if (process._eval != null) {
83       // User passed '-e' or '--eval' arguments to Node.
84       evalScript('[eval]');
85     } else if (process.argv[1]) {
86       // make process.argv[1] into a full path
87       var path = NativeModule.require('path');
88       process.argv[1] = path.resolve(process.argv[1]);
89
90       // If this is a worker in cluster mode, start up the communication
91       // channel.
92       if (process.env.NODE_UNIQUE_ID) {
93         var cluster = NativeModule.require('cluster');
94         cluster._setupWorker();
95
96         // Make sure it's not accidentally inherited by child processes.
97         delete process.env.NODE_UNIQUE_ID;
98       }
99
100       var Module = NativeModule.require('module');
101
102       if (global.v8debug &&
103           process.execArgv.some(function(arg) {
104             return arg.match(/^--debug-brk(=[0-9]*)?$/);
105           })) {
106
107         // XXX Fix this terrible hack!
108         //
109         // Give the client program a few ticks to connect.
110         // Otherwise, there's a race condition where `node debug foo.js`
111         // will not be able to connect in time to catch the first
112         // breakpoint message on line 1.
113         //
114         // A better fix would be to somehow get a message from the
115         // global.v8debug object about a connection, and runMain when
116         // that occurs.  --isaacs
117
118         var debugTimeout = +process.env.NODE_DEBUG_TIMEOUT || 50;
119         setTimeout(Module.runMain, debugTimeout);
120
121       } else {
122         // Main entry point into most programs:
123         Module.runMain();
124       }
125
126     } else {
127       var Module = NativeModule.require('module');
128
129       // If -i or --interactive were passed, or stdin is a TTY.
130       if (process._forceRepl || NativeModule.require('tty').isatty(0)) {
131         // REPL
132         var opts = {
133           useGlobal: true,
134           ignoreUndefined: false
135         };
136         if (parseInt(process.env['NODE_NO_READLINE'], 10)) {
137           opts.terminal = false;
138         }
139         if (parseInt(process.env['NODE_DISABLE_COLORS'], 10)) {
140           opts.useColors = false;
141         }
142         var repl = Module.requireRepl().start(opts);
143         repl.on('exit', function() {
144           process.exit();
145         });
146
147       } else {
148         // Read all of stdin - execute it.
149         process.stdin.setEncoding('utf8');
150
151         var code = '';
152         process.stdin.on('data', function(d) {
153           code += d;
154         });
155
156         process.stdin.on('end', function() {
157           process._eval = code;
158           evalScript('[stdin]');
159         });
160       }
161     }
162   }
163
164   startup.globalVariables = function() {
165     global.process = process;
166     global.global = global;
167     global.GLOBAL = global;
168     global.root = global;
169     global.Buffer = NativeModule.require('buffer').Buffer;
170     process.domain = null;
171     process._exiting = false;
172   };
173
174   startup.globalTimeouts = function() {
175     global.setTimeout = function() {
176       var t = NativeModule.require('timers');
177       return t.setTimeout.apply(this, arguments);
178     };
179
180     global.setInterval = function() {
181       var t = NativeModule.require('timers');
182       return t.setInterval.apply(this, arguments);
183     };
184
185     global.clearTimeout = function() {
186       var t = NativeModule.require('timers');
187       return t.clearTimeout.apply(this, arguments);
188     };
189
190     global.clearInterval = function() {
191       var t = NativeModule.require('timers');
192       return t.clearInterval.apply(this, arguments);
193     };
194
195     global.setImmediate = function() {
196       var t = NativeModule.require('timers');
197       return t.setImmediate.apply(this, arguments);
198     };
199
200     global.clearImmediate = function() {
201       var t = NativeModule.require('timers');
202       return t.clearImmediate.apply(this, arguments);
203     };
204   };
205
206   startup.globalConsole = function() {
207     global.__defineGetter__('console', function() {
208       return NativeModule.require('console');
209     });
210   };
211
212
213   startup._lazyConstants = null;
214
215   startup.lazyConstants = function() {
216     if (!startup._lazyConstants) {
217       startup._lazyConstants = process.binding('constants');
218     }
219     return startup._lazyConstants;
220   };
221
222   startup.processFatal = function() {
223     process._fatalException = function(er) {
224       // First run through error handlers from asyncListener.
225       var caught = _errorHandler(er);
226
227       if (!caught)
228         caught = process.emit('uncaughtException', er);
229
230       // If someone handled it, then great. Otherwise die in C++ since
231       // that means we'll exit the process, emit the 'exit' event.
232       if (!caught) {
233         try {
234           if (!process._exiting) {
235             process._exiting = true;
236             process.emit('exit', 1);
237           }
238         } catch (er) {
239           // nothing to be done about it at this point.
240         }
241
242       // if we handled an error, then make sure any ticks get processed
243       } else {
244         var t = setImmediate(process._tickCallback);
245         // Complete hack to make sure any errors thrown from async
246         // listeners don't cause an infinite loop.
247         if (t._asyncQueue)
248           t._asyncQueue = [];
249       }
250
251       return caught;
252     };
253   };
254
255   startup.processAsyncListener = function() {
256     var asyncStack = [];
257     var asyncQueue = [];
258     var uid = 0;
259
260     // Stateful flags shared with Environment for quick JS/C++
261     // communication.
262     var asyncFlags = {};
263
264     // Prevent accidentally suppressed thrown errors from before/after.
265     var inAsyncTick = false;
266
267     // To prevent infinite recursion when an error handler also throws
268     // flag when an error is currenly being handled.
269     var inErrorTick = false;
270
271     // Needs to be the same as src/env.h
272     var kCount = 0;
273
274     // _errorHandler is scoped so it's also accessible by _fatalException.
275     _errorHandler = errorHandler;
276
277     // Needs to be accessible from lib/timers.js so they know when async
278     // listeners are currently in queue. They'll be cleaned up once
279     // references there are made.
280     process._asyncFlags = asyncFlags;
281     process._runAsyncQueue = runAsyncQueue;
282     process._loadAsyncQueue = loadAsyncQueue;
283     process._unloadAsyncQueue = unloadAsyncQueue;
284
285     // Public API.
286     process.createAsyncListener = createAsyncListener;
287     process.addAsyncListener = addAsyncListener;
288     process.removeAsyncListener = removeAsyncListener;
289
290     // Setup shared objects/callbacks with native layer.
291     process._setupAsyncListener(asyncFlags,
292                                 runAsyncQueue,
293                                 loadAsyncQueue,
294                                 unloadAsyncQueue,
295                                 pushListener,
296                                 stripListener);
297
298     function popQueue() {
299       if (asyncStack.length > 0)
300         asyncQueue = asyncStack.pop();
301       else
302         asyncQueue = [];
303     }
304
305     // Run all the async listeners attached when an asynchronous event is
306     // instantiated.
307     function runAsyncQueue(context) {
308       var queue = [];
309       var queueItem, item, i, value;
310
311       inAsyncTick = true;
312       for (i = 0; i < asyncQueue.length; i++) {
313         queueItem = asyncQueue[i];
314         if (!queueItem.callbacks.create) {
315           queue[i] = queueItem;
316           continue;
317         }
318         // Not passing "this" context because it hasn't actually been
319         // instantiated yet, so accessing some of the object properties
320         // can cause a segfault.
321         // Passing the original value will allow users to manipulate the
322         // original value object, while also allowing them to return a
323         // new value for current async call tracking.
324         value = queueItem.callbacks.create(queueItem.value);
325         if (typeof value !== 'undefined') {
326           item = {
327             callbacks: queueItem.callbacks,
328             value: value,
329             uid: queueItem.uid
330           };
331         } else {
332           item = queueItem;
333         }
334         queue[i] = item;
335       }
336       inAsyncTick = false;
337
338       context._asyncQueue = queue;
339     }
340
341     // Uses the _asyncQueue object attached by runAsyncQueue.
342     function loadAsyncQueue(context) {
343       var queue = context._asyncQueue;
344       var item, before, i;
345
346       asyncStack.push(asyncQueue);
347       asyncQueue = queue.slice();
348       // Since the async listener callback is required, the number of
349       // objects in the asyncQueue implies the number of async listeners
350       // there are to be processed.
351       asyncFlags[kCount] = queue.length;
352
353       // Run "before" callbacks.
354       inAsyncTick = true;
355       for (i = 0; i < queue.length; i++) {
356         item = queue[i];
357         if (!item.callbacks)
358           continue;
359         before = item.callbacks.before;
360         if (typeof before === 'function')
361           before(context, item.value);
362       }
363       inAsyncTick = false;
364     }
365
366     // Unload one level of the async stack. Returns true if there are
367     // still listeners somewhere in the stack.
368     function unloadAsyncQueue(context) {
369       var queue = context._asyncQueue;
370       var item, after, i;
371
372       // Run "after" callbacks.
373       inAsyncTick = true;
374       for (i = 0; i < queue.length; i++) {
375         item = queue[i];
376         if (!item.callbacks)
377           continue;
378         after = item.callbacks.after;
379         if (typeof after === 'function')
380           after(context, item.value);
381       }
382       inAsyncTick = false;
383
384       // Unload the current queue from the stack.
385       popQueue();
386
387       asyncFlags[kCount] = asyncQueue.length;
388
389       return asyncQueue.length > 0 || asyncStack.length > 0;
390     }
391
392     // Create new async listener object. Useful when instantiating a new
393     // object and want the listener instance, but not add it to the stack.
394     function createAsyncListener(callbacks, value) {
395       return {
396         callbacks: callbacks,
397         value: value,
398         uid: uid++
399       };
400     }
401
402     // Add a listener to the current queue.
403     function addAsyncListener(callbacks, value) {
404       // Accept new listeners or previous created listeners.
405       if (typeof callbacks.uid !== 'number')
406         callbacks = createAsyncListener(callbacks, value);
407
408       var inQueue = false;
409       // The asyncQueue will be small. Probably always <= 3 items.
410       for (var i = 0; i < asyncQueue.length; i++) {
411         if (callbacks.uid === asyncQueue[i].uid) {
412           inQueue = true;
413           break;
414         }
415       }
416
417       // Make sure the callback doesn't already exist in the queue.
418       if (!inQueue)
419         asyncQueue.push(callbacks);
420
421       asyncFlags[kCount] = asyncQueue.length;
422       return callbacks;
423     }
424
425     // Remove listener from the current queue and the entire stack.
426     function removeAsyncListener(obj) {
427       var i, j;
428
429       for (i = 0; i < asyncQueue.length; i++) {
430         if (obj.uid === asyncQueue[i].uid) {
431           asyncQueue.splice(i, 1);
432           break;
433         }
434       }
435
436       for (i = 0; i < asyncStack.length; i++) {
437         for (j = 0; j < asyncStack[i].length; j++) {
438           if (obj.uid === asyncStack[i][j].uid) {
439             asyncStack[i].splice(j, 1);
440             break;
441           }
442         }
443       }
444
445       asyncFlags[kCount] = asyncQueue.length;
446     }
447
448     // Error handler used by _fatalException to run through all error
449     // callbacks in the current asyncQueue.
450     function errorHandler(er) {
451       var handled = false;
452       var error, item, i;
453
454       if (inErrorTick)
455         return false;
456
457       inErrorTick = true;
458       for (i = 0; i < asyncQueue.length; i++) {
459         item = asyncQueue[i];
460         if (!item.callbacks)
461           continue;
462         error = item.callbacks.error;
463         if (typeof error === 'function') {
464           try {
465             var threw = true;
466             handled = error(item.value, er) || handled;
467             threw = false;
468           } finally {
469             // If the error callback throws then we're going to die
470             // quickly with no chance of recovery. Only thing we're going
471             // to allow is execution of process exit event callbacks.
472             if (threw) {
473               process._exiting = true;
474               process.emit('exit', 1);
475             }
476           }
477         }
478       }
479       inErrorTick = false;
480
481       // Unload the current queue from the stack.
482       popQueue();
483
484       return handled && !inAsyncTick;
485     }
486
487     // Used by AsyncWrap::AddAsyncListener() to add an individual listener
488     // to the async queue. It will check the uid of the listener and only
489     // allow it to be added once.
490     function pushListener(obj) {
491       if (!this._asyncQueue)
492         this._asyncQueue = [];
493
494       var queue = this._asyncQueue;
495       var inQueue = false;
496       // The asyncQueue will be small. Probably always <= 3 items.
497       for (var i = 0; i < queue.length; i++) {
498         if (obj.uid === queue[i].uid) {
499           inQueue = true;
500           break;
501         }
502       }
503
504       if (!inQueue)
505         queue.push(obj);
506     }
507
508     // Used by AsyncWrap::RemoveAsyncListener() to remove an individual
509     // listener from the async queue, and return whether there are still
510     // listeners in the queue.
511     function stripListener(obj) {
512       if (!this._asyncQueue || this._asyncQueue.length === 0)
513         return false;
514
515       // The asyncQueue will be small. Probably always <= 3 items.
516       for (var i = 0; i < this._asyncQueue.length; i++) {
517         if (obj.uid === this._asyncQueue[i].uid) {
518           this._asyncQueue.splice(i, 1);
519           break;
520         }
521       }
522
523       return this._asyncQueue.length > 0;
524     }
525   };
526
527   var assert;
528   startup.processAssert = function() {
529     assert = process.assert = function(x, msg) {
530       if (!x) throw new Error(msg || 'assertion error');
531     };
532   };
533
534   startup.processConfig = function() {
535     // used for `process.config`, but not a real module
536     var config = NativeModule._source.config;
537     delete NativeModule._source.config;
538
539     // strip the gyp comment line at the beginning
540     config = config.split('\n').slice(1).join('\n').replace(/'/g, '"');
541
542     process.config = JSON.parse(config, function(key, value) {
543       if (value === 'true') return true;
544       if (value === 'false') return false;
545       return value;
546     });
547   };
548
549   startup.processNextTick = function() {
550     var nextTickQueue = [];
551     var asyncFlags = process._asyncFlags;
552     var _runAsyncQueue = process._runAsyncQueue;
553     var _loadAsyncQueue = process._loadAsyncQueue;
554     var _unloadAsyncQueue = process._unloadAsyncQueue;
555
556     // This tickInfo thing is used so that the C++ code in src/node.cc
557     // can have easy accesss to our nextTick state, and avoid unnecessary
558     var tickInfo = {};
559
560     // *Must* match Environment::TickInfo::Fields in src/env.h.
561     var kIndex = 0;
562     var kLength = 1;
563
564     // For asyncFlags.
565     // *Must* match Environment::AsyncListeners::Fields in src/env.h
566     var kCount = 0;
567
568     process.nextTick = nextTick;
569     // Needs to be accessible from beyond this scope.
570     process._tickCallback = _tickCallback;
571
572     process._setupNextTick(tickInfo, _tickCallback);
573
574     function tickDone() {
575       if (tickInfo[kLength] !== 0) {
576         if (tickInfo[kLength] <= tickInfo[kIndex]) {
577           nextTickQueue = [];
578           tickInfo[kLength] = 0;
579         } else {
580           nextTickQueue.splice(0, tickInfo[kIndex]);
581           tickInfo[kLength] = nextTickQueue.length;
582         }
583       }
584       tickInfo[kIndex] = 0;
585     }
586
587     // Run callbacks that have no domain.
588     function _tickCallback() {
589       var callback, hasQueue, threw, tock;
590
591       while (tickInfo[kIndex] < tickInfo[kLength]) {
592         tock = nextTickQueue[tickInfo[kIndex]++];
593         callback = tock.callback;
594         threw = true;
595         hasQueue = !!tock._asyncQueue;
596         if (hasQueue)
597           _loadAsyncQueue(tock);
598         try {
599           callback();
600           threw = false;
601         } finally {
602           if (threw)
603             tickDone();
604         }
605         if (hasQueue)
606           _unloadAsyncQueue(tock);
607         if (1e4 < tickInfo[kIndex])
608           tickDone();
609       }
610
611       tickDone();
612     }
613
614     function nextTick(callback) {
615       // on the way out, don't bother. it won't get fired anyway.
616       if (process._exiting)
617         return;
618
619       var obj = {
620         callback: callback,
621         _asyncQueue: undefined
622       };
623
624       if (asyncFlags[kCount] > 0)
625         _runAsyncQueue(obj);
626
627       nextTickQueue.push(obj);
628       tickInfo[kLength]++;
629     }
630   };
631
632   function evalScript(name) {
633     var Module = NativeModule.require('module');
634     var path = NativeModule.require('path');
635     var cwd = process.cwd();
636
637     var module = new Module(name);
638     module.filename = path.join(cwd, name);
639     module.paths = Module._nodeModulePaths(cwd);
640     var script = process._eval;
641     if (!Module._contextLoad) {
642       var body = script;
643       script = 'global.__filename = ' + JSON.stringify(name) + ';\n' +
644                'global.exports = exports;\n' +
645                'global.module = module;\n' +
646                'global.__dirname = __dirname;\n' +
647                'global.require = require;\n' +
648                'return require("vm").runInThisContext(' +
649                JSON.stringify(body) + ', { filename: ' +
650                JSON.stringify(name) + ' });\n';
651     }
652     var result = module._compile(script, name + '-wrapper');
653     if (process._print_eval) console.log(result);
654   }
655
656   function createWritableStdioStream(fd) {
657     var stream;
658     var tty_wrap = process.binding('tty_wrap');
659
660     // Note stream._type is used for test-module-load-list.js
661
662     switch (tty_wrap.guessHandleType(fd)) {
663       case 'TTY':
664         var tty = NativeModule.require('tty');
665         stream = new tty.WriteStream(fd);
666         stream._type = 'tty';
667
668         // Hack to have stream not keep the event loop alive.
669         // See https://github.com/joyent/node/issues/1726
670         if (stream._handle && stream._handle.unref) {
671           stream._handle.unref();
672         }
673         break;
674
675       case 'FILE':
676         var fs = NativeModule.require('fs');
677         stream = new fs.SyncWriteStream(fd);
678         stream._type = 'fs';
679         break;
680
681       case 'PIPE':
682       case 'TCP':
683         var net = NativeModule.require('net');
684         stream = new net.Socket({
685           fd: fd,
686           readable: false,
687           writable: true
688         });
689
690         // FIXME Should probably have an option in net.Socket to create a
691         // stream from an existing fd which is writable only. But for now
692         // we'll just add this hack and set the `readable` member to false.
693         // Test: ./node test/fixtures/echo.js < /etc/passwd
694         stream.readable = false;
695         stream.read = null;
696         stream._type = 'pipe';
697
698         // FIXME Hack to have stream not keep the event loop alive.
699         // See https://github.com/joyent/node/issues/1726
700         if (stream._handle && stream._handle.unref) {
701           stream._handle.unref();
702         }
703         break;
704
705       default:
706         // Probably an error on in uv_guess_handle()
707         throw new Error('Implement me. Unknown stream file type!');
708     }
709
710     // For supporting legacy API we put the FD here.
711     stream.fd = fd;
712
713     stream._isStdio = true;
714
715     return stream;
716   }
717
718   startup.processStdio = function() {
719     var stdin, stdout, stderr;
720
721     process.__defineGetter__('stdout', function() {
722       if (stdout) return stdout;
723       stdout = createWritableStdioStream(1);
724       stdout.destroy = stdout.destroySoon = function(er) {
725         er = er || new Error('process.stdout cannot be closed.');
726         stdout.emit('error', er);
727       };
728       if (stdout.isTTY) {
729         process.on('SIGWINCH', function() {
730           stdout._refreshSize();
731         });
732       }
733       return stdout;
734     });
735
736     process.__defineGetter__('stderr', function() {
737       if (stderr) return stderr;
738       stderr = createWritableStdioStream(2);
739       stderr.destroy = stderr.destroySoon = function(er) {
740         er = er || new Error('process.stderr cannot be closed.');
741         stderr.emit('error', er);
742       };
743       return stderr;
744     });
745
746     process.__defineGetter__('stdin', function() {
747       if (stdin) return stdin;
748
749       var tty_wrap = process.binding('tty_wrap');
750       var fd = 0;
751
752       switch (tty_wrap.guessHandleType(fd)) {
753         case 'TTY':
754           var tty = NativeModule.require('tty');
755           stdin = new tty.ReadStream(fd, {
756             highWaterMark: 0,
757             readable: true,
758             writable: false
759           });
760           break;
761
762         case 'FILE':
763           var fs = NativeModule.require('fs');
764           stdin = new fs.ReadStream(null, { fd: fd });
765           break;
766
767         case 'PIPE':
768         case 'TCP':
769           var net = NativeModule.require('net');
770           stdin = new net.Socket({
771             fd: fd,
772             readable: true,
773             writable: false
774           });
775           break;
776
777         default:
778           // Probably an error on in uv_guess_handle()
779           throw new Error('Implement me. Unknown stdin file type!');
780       }
781
782       // For supporting legacy API we put the FD here.
783       stdin.fd = fd;
784
785       // stdin starts out life in a paused state, but node doesn't
786       // know yet.  Explicitly to readStop() it to put it in the
787       // not-reading state.
788       if (stdin._handle && stdin._handle.readStop) {
789         stdin._handle.reading = false;
790         stdin._readableState.reading = false;
791         stdin._handle.readStop();
792       }
793
794       // if the user calls stdin.pause(), then we need to stop reading
795       // immediately, so that the process can close down.
796       stdin.on('pause', function() {
797         if (!stdin._handle)
798           return;
799         stdin._readableState.reading = false;
800         stdin._handle.reading = false;
801         stdin._handle.readStop();
802       });
803
804       return stdin;
805     });
806
807     process.openStdin = function() {
808       process.stdin.resume();
809       return process.stdin;
810     };
811   };
812
813   startup.processKillAndExit = function() {
814     process.exitCode = 0;
815     process.exit = function(code) {
816       if (code || code === 0)
817         process.exitCode = code;
818
819       if (!process._exiting) {
820         process._exiting = true;
821         process.emit('exit', process.exitCode || 0);
822       }
823       process.reallyExit(process.exitCode || 0);
824     };
825
826     process.kill = function(pid, sig) {
827       var err;
828
829       // preserve null signal
830       if (0 === sig) {
831         err = process._kill(pid, 0);
832       } else {
833         sig = sig || 'SIGTERM';
834         if (startup.lazyConstants()[sig] &&
835             sig.slice(0, 3) === 'SIG') {
836           err = process._kill(pid, startup.lazyConstants()[sig]);
837         } else {
838           throw new Error('Unknown signal: ' + sig);
839         }
840       }
841
842       if (err) {
843         var errnoException = NativeModule.require('util')._errnoException;
844         throw errnoException(err, 'kill');
845       }
846
847       return true;
848     };
849   };
850
851   startup.processSignalHandlers = function() {
852     // Load events module in order to access prototype elements on process like
853     // process.addListener.
854     var signalWraps = {};
855     var addListener = process.addListener;
856     var removeListener = process.removeListener;
857
858     function isSignal(event) {
859       return event.slice(0, 3) === 'SIG' &&
860              startup.lazyConstants().hasOwnProperty(event);
861     }
862
863     // Wrap addListener for the special signal types
864     process.on = process.addListener = function(type, listener) {
865       if (isSignal(type) &&
866           !signalWraps.hasOwnProperty(type)) {
867         var Signal = process.binding('signal_wrap').Signal;
868         var wrap = new Signal();
869
870         wrap.unref();
871
872         wrap.onsignal = function() { process.emit(type); };
873
874         var signum = startup.lazyConstants()[type];
875         var err = wrap.start(signum);
876         if (err) {
877           wrap.close();
878           var errnoException = NativeModule.require('util')._errnoException;
879           throw errnoException(err, 'uv_signal_start');
880         }
881
882         signalWraps[type] = wrap;
883       }
884
885       return addListener.apply(this, arguments);
886     };
887
888     process.removeListener = function(type, listener) {
889       var ret = removeListener.apply(this, arguments);
890       if (isSignal(type)) {
891         assert(signalWraps.hasOwnProperty(type));
892
893         if (this.listeners(type).length === 0) {
894           signalWraps[type].close();
895           delete signalWraps[type];
896         }
897       }
898
899       return ret;
900     };
901   };
902
903
904   startup.processChannel = function() {
905     // If we were spawned with env NODE_CHANNEL_FD then load that up and
906     // start parsing data from that stream.
907     if (process.env.NODE_CHANNEL_FD) {
908       var fd = parseInt(process.env.NODE_CHANNEL_FD, 10);
909       assert(fd >= 0);
910
911       // Make sure it's not accidentally inherited by child processes.
912       delete process.env.NODE_CHANNEL_FD;
913
914       var cp = NativeModule.require('child_process');
915
916       // Load tcp_wrap to avoid situation where we might immediately receive
917       // a message.
918       // FIXME is this really necessary?
919       process.binding('tcp_wrap');
920
921       cp._forkChild(fd);
922       assert(process.send);
923     }
924   };
925
926
927   startup.processRawDebug = function() {
928     var format = NativeModule.require('util').format;
929     var rawDebug = process._rawDebug;
930     process._rawDebug = function() {
931       rawDebug(format.apply(null, arguments));
932     };
933   };
934
935
936   startup.resolveArgv0 = function() {
937     var cwd = process.cwd();
938     var isWindows = process.platform === 'win32';
939
940     // Make process.argv[0] into a full path, but only touch argv[0] if it's
941     // not a system $PATH lookup.
942     // TODO: Make this work on Windows as well.  Note that "node" might
943     // execute cwd\node.exe, or some %PATH%\node.exe on Windows,
944     // and that every directory has its own cwd, so d:node.exe is valid.
945     var argv0 = process.argv[0];
946     if (!isWindows && argv0.indexOf('/') !== -1 && argv0.charAt(0) !== '/') {
947       var path = NativeModule.require('path');
948       process.argv[0] = path.join(cwd, process.argv[0]);
949     }
950   };
951
952   // Below you find a minimal module system, which is used to load the node
953   // core modules found in lib/*.js. All core modules are compiled into the
954   // node binary, so they can be loaded faster.
955
956   var ContextifyScript = process.binding('contextify').ContextifyScript;
957   function runInThisContext(code, options) {
958     var script = new ContextifyScript(code, options);
959     return script.runInThisContext();
960   }
961
962   function NativeModule(id) {
963     this.filename = id + '.js';
964     this.id = id;
965     this.exports = {};
966     this.loaded = false;
967   }
968
969   NativeModule._source = process.binding('natives');
970   NativeModule._cache = {};
971
972   NativeModule.require = function(id) {
973     if (id == 'native_module') {
974       return NativeModule;
975     }
976
977     var cached = NativeModule.getCached(id);
978     if (cached) {
979       return cached.exports;
980     }
981
982     if (!NativeModule.exists(id)) {
983       throw new Error('No such native module ' + id);
984     }
985
986     process.moduleLoadList.push('NativeModule ' + id);
987
988     var nativeModule = new NativeModule(id);
989
990     nativeModule.cache();
991     nativeModule.compile();
992
993     return nativeModule.exports;
994   };
995
996   NativeModule.getCached = function(id) {
997     return NativeModule._cache[id];
998   }
999
1000   NativeModule.exists = function(id) {
1001     return NativeModule._source.hasOwnProperty(id);
1002   }
1003
1004   NativeModule.getSource = function(id) {
1005     return NativeModule._source[id];
1006   }
1007
1008   NativeModule.wrap = function(script) {
1009     return NativeModule.wrapper[0] + script + NativeModule.wrapper[1];
1010   };
1011
1012   NativeModule.wrapper = [
1013     '(function (exports, require, module, __filename, __dirname) { ',
1014     '\n});'
1015   ];
1016
1017   NativeModule.prototype.compile = function() {
1018     var source = NativeModule.getSource(this.id);
1019     source = NativeModule.wrap(source);
1020
1021     var fn = runInThisContext(source, { filename: this.filename });
1022     fn(this.exports, NativeModule.require, this, this.filename);
1023
1024     this.loaded = true;
1025   };
1026
1027   NativeModule.prototype.cache = function() {
1028     NativeModule._cache[this.id] = this;
1029   };
1030
1031   startup();
1032 });