1 // Copyright Joyent, Inc. and other Node contributors.
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:
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
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.
22 // Hello, and welcome to hacking node.js!
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.
31 var EventEmitter = NativeModule.require('events').EventEmitter;
33 process.__proto__ = Object.create(EventEmitter.prototype, {
35 value: process.constructor
38 EventEmitter.call(process);
40 process.EventEmitter = EventEmitter; // process.EventEmitter is deprecated
42 // Setup the tracing module
43 NativeModule.require('tracing')._nodeInitialization(process);
45 // do this good and early, since it handles errors.
46 startup.processFatal();
48 startup.globalVariables();
49 startup.globalTimeouts();
50 startup.globalConsole();
52 startup.processAssert();
53 startup.processConfig();
54 startup.processNextTick();
55 startup.processStdio();
56 startup.processKillAndExit();
57 startup.processSignalHandlers();
59 // Do not initialize channel in debugger agent, it deletes env variable
60 // and the main thread won't see it.
61 if (process.argv[1] !== '--debug-agent')
62 startup.processChannel();
64 startup.processRawDebug();
66 startup.resolveArgv0();
68 // There are various modes that Node can run in. The most common two
69 // are running from a script and running the REPL - but there are a few
70 // others like the debugger or running --eval arguments. Here we decide
71 // which mode we run in.
73 if (NativeModule.exists('_third_party_main')) {
74 // To allow people to extend Node in different ways, this hook allows
75 // one to drop a file lib/_third_party_main.js into the build
76 // directory which will be executed instead of Node's normal loading.
77 process.nextTick(function() {
78 NativeModule.require('_third_party_main');
81 } else if (process.argv[1] == 'debug') {
82 // Start the debugger agent
83 var d = NativeModule.require('_debugger');
86 } else if (process.argv[1] == '--debug-agent') {
87 // Start the debugger agent
88 var d = NativeModule.require('_debug_agent');
91 } else if (process._eval != null) {
92 // User passed '-e' or '--eval' arguments to Node.
94 } else if (process.argv[1]) {
95 // make process.argv[1] into a full path
96 var path = NativeModule.require('path');
97 process.argv[1] = path.resolve(process.argv[1]);
99 // If this is a worker in cluster mode, start up the communication
101 if (process.env.NODE_UNIQUE_ID) {
102 var cluster = NativeModule.require('cluster');
103 cluster._setupWorker();
105 // Make sure it's not accidentally inherited by child processes.
106 delete process.env.NODE_UNIQUE_ID;
109 var Module = NativeModule.require('module');
111 if (global.v8debug &&
112 process.execArgv.some(function(arg) {
113 return arg.match(/^--debug-brk(=[0-9]*)?$/);
116 // XXX Fix this terrible hack!
118 // Give the client program a few ticks to connect.
119 // Otherwise, there's a race condition where `node debug foo.js`
120 // will not be able to connect in time to catch the first
121 // breakpoint message on line 1.
123 // A better fix would be to somehow get a message from the
124 // global.v8debug object about a connection, and runMain when
125 // that occurs. --isaacs
127 var debugTimeout = +process.env.NODE_DEBUG_TIMEOUT || 50;
128 setTimeout(Module.runMain, debugTimeout);
131 // Main entry point into most programs:
136 var Module = NativeModule.require('module');
138 // If -i or --interactive were passed, or stdin is a TTY.
139 if (process._forceRepl || NativeModule.require('tty').isatty(0)) {
143 ignoreUndefined: false
145 if (parseInt(process.env['NODE_NO_READLINE'], 10)) {
146 opts.terminal = false;
148 if (parseInt(process.env['NODE_DISABLE_COLORS'], 10)) {
149 opts.useColors = false;
151 var repl = Module.requireRepl().start(opts);
152 repl.on('exit', function() {
157 // Read all of stdin - execute it.
158 process.stdin.setEncoding('utf8');
161 process.stdin.on('data', function(d) {
165 process.stdin.on('end', function() {
166 process._eval = code;
167 evalScript('[stdin]');
173 startup.globalVariables = function() {
174 global.process = process;
175 global.global = global;
176 global.GLOBAL = global;
177 global.root = global;
178 global.Buffer = NativeModule.require('buffer').Buffer;
179 process.domain = null;
180 process._exiting = false;
183 startup.globalTimeouts = function() {
184 global.setTimeout = function() {
185 var t = NativeModule.require('timers');
186 return t.setTimeout.apply(this, arguments);
189 global.setInterval = function() {
190 var t = NativeModule.require('timers');
191 return t.setInterval.apply(this, arguments);
194 global.clearTimeout = function() {
195 var t = NativeModule.require('timers');
196 return t.clearTimeout.apply(this, arguments);
199 global.clearInterval = function() {
200 var t = NativeModule.require('timers');
201 return t.clearInterval.apply(this, arguments);
204 global.setImmediate = function() {
205 var t = NativeModule.require('timers');
206 return t.setImmediate.apply(this, arguments);
209 global.clearImmediate = function() {
210 var t = NativeModule.require('timers');
211 return t.clearImmediate.apply(this, arguments);
215 startup.globalConsole = function() {
216 global.__defineGetter__('console', function() {
217 return NativeModule.require('console');
222 startup._lazyConstants = null;
224 startup.lazyConstants = function() {
225 if (!startup._lazyConstants) {
226 startup._lazyConstants = process.binding('constants');
228 return startup._lazyConstants;
231 startup.processFatal = function() {
232 var tracing = NativeModule.require('tracing');
233 var _errorHandler = tracing._errorHandler;
235 delete tracing._errorHandler;
237 process._fatalException = function(er) {
238 // First run through error handlers from asyncListener.
239 var caught = _errorHandler(er);
241 if (process.domain && process.domain._errorHandler)
242 caught = process.domain._errorHandler(er) || caught;
245 caught = process.emit('uncaughtException', er);
247 // If someone handled it, then great. otherwise, die in C++ land
248 // since that means that we'll exit the process, emit the 'exit' event
251 if (!process._exiting) {
252 process._exiting = true;
253 process.emit('exit', 1);
256 // nothing to be done about it at this point.
259 // if we handled an error, then make sure any ticks get processed
261 var t = setImmediate(process._tickCallback);
262 // Complete hack to make sure any errors thrown from async
263 // listeners don't cause an infinite loop.
273 startup.processAssert = function() {
274 assert = process.assert = function(x, msg) {
275 if (!x) throw new Error(msg || 'assertion error');
279 startup.processConfig = function() {
280 // used for `process.config`, but not a real module
281 var config = NativeModule._source.config;
282 delete NativeModule._source.config;
284 // strip the gyp comment line at the beginning
285 config = config.split('\n')
288 .replace(/"/g, '\\"')
291 process.config = JSON.parse(config, function(key, value) {
292 if (value === 'true') return true;
293 if (value === 'false') return false;
298 startup.processNextTick = function() {
299 var tracing = NativeModule.require('tracing');
300 var nextTickQueue = [];
301 var asyncFlags = tracing._asyncFlags;
302 var _runAsyncQueue = tracing._runAsyncQueue;
303 var _loadAsyncQueue = tracing._loadAsyncQueue;
304 var _unloadAsyncQueue = tracing._unloadAsyncQueue;
305 var microtasksScheduled = false;
307 // Used to run V8's micro task queue.
308 var _runMicrotasks = {};
310 // This tickInfo thing is used so that the C++ code in src/node.cc
311 // can have easy accesss to our nextTick state, and avoid unnecessary
314 // *Must* match Environment::TickInfo::Fields in src/env.h.
319 // *Must* match Environment::AsyncListeners::Fields in src/env.h
322 process.nextTick = nextTick;
323 // Needs to be accessible from beyond this scope.
324 process._tickCallback = _tickCallback;
325 process._tickDomainCallback = _tickDomainCallback;
327 process._setupNextTick(tickInfo, _tickCallback, _runMicrotasks);
329 _runMicrotasks = _runMicrotasks.runMicrotasks;
331 function tickDone() {
332 if (tickInfo[kLength] !== 0) {
333 if (tickInfo[kLength] <= tickInfo[kIndex]) {
335 tickInfo[kLength] = 0;
337 nextTickQueue.splice(0, tickInfo[kIndex]);
338 tickInfo[kLength] = nextTickQueue.length;
341 tickInfo[kIndex] = 0;
344 function scheduleMicrotasks() {
345 if (microtasksScheduled)
349 callback: runMicrotasksCallback,
354 microtasksScheduled = true;
357 function runMicrotasksCallback() {
358 microtasksScheduled = false;
361 if (tickInfo[kIndex] < tickInfo[kLength])
362 scheduleMicrotasks();
365 // Run callbacks that have no domain.
366 // Using domains will cause this to be overridden.
367 function _tickCallback() {
368 var callback, hasQueue, threw, tock;
370 scheduleMicrotasks();
372 while (tickInfo[kIndex] < tickInfo[kLength]) {
373 tock = nextTickQueue[tickInfo[kIndex]++];
374 callback = tock.callback;
376 hasQueue = !!tock._asyncQueue;
378 _loadAsyncQueue(tock);
387 _unloadAsyncQueue(tock);
388 if (1e4 < tickInfo[kIndex])
395 function _tickDomainCallback() {
396 var callback, domain, hasQueue, threw, tock;
398 scheduleMicrotasks();
400 while (tickInfo[kIndex] < tickInfo[kLength]) {
401 tock = nextTickQueue[tickInfo[kIndex]++];
402 callback = tock.callback;
403 domain = tock.domain;
404 hasQueue = !!tock._asyncQueue;
406 _loadAsyncQueue(tock);
418 _unloadAsyncQueue(tock);
419 if (1e4 < tickInfo[kIndex])
428 function nextTick(callback) {
429 // on the way out, don't bother. it won't get fired anyway.
430 if (process._exiting)
435 domain: process.domain || null,
436 _asyncQueue: undefined
439 if (asyncFlags[kCount] > 0)
442 nextTickQueue.push(obj);
447 function evalScript(name) {
448 var Module = NativeModule.require('module');
449 var path = NativeModule.require('path');
450 var cwd = process.cwd();
452 var module = new Module(name);
453 module.filename = path.join(cwd, name);
454 module.paths = Module._nodeModulePaths(cwd);
455 var script = process._eval;
456 if (!Module._contextLoad) {
458 script = 'global.__filename = ' + JSON.stringify(name) + ';\n' +
459 'global.exports = exports;\n' +
460 'global.module = module;\n' +
461 'global.__dirname = __dirname;\n' +
462 'global.require = require;\n' +
463 'return require("vm").runInThisContext(' +
464 JSON.stringify(body) + ', { filename: ' +
465 JSON.stringify(name) + ' });\n';
467 var result = module._compile(script, name + '-wrapper');
468 if (process._print_eval) console.log(result);
471 function createWritableStdioStream(fd) {
473 var tty_wrap = process.binding('tty_wrap');
475 // Note stream._type is used for test-module-load-list.js
477 switch (tty_wrap.guessHandleType(fd)) {
479 var tty = NativeModule.require('tty');
480 stream = new tty.WriteStream(fd);
481 stream._type = 'tty';
483 // Hack to have stream not keep the event loop alive.
484 // See https://github.com/joyent/node/issues/1726
485 if (stream._handle && stream._handle.unref) {
486 stream._handle.unref();
491 var fs = NativeModule.require('fs');
492 stream = new fs.SyncWriteStream(fd, { autoClose: false });
498 var net = NativeModule.require('net');
499 stream = new net.Socket({
505 // FIXME Should probably have an option in net.Socket to create a
506 // stream from an existing fd which is writable only. But for now
507 // we'll just add this hack and set the `readable` member to false.
508 // Test: ./node test/fixtures/echo.js < /etc/passwd
509 stream.readable = false;
511 stream._type = 'pipe';
513 // FIXME Hack to have stream not keep the event loop alive.
514 // See https://github.com/joyent/node/issues/1726
515 if (stream._handle && stream._handle.unref) {
516 stream._handle.unref();
521 // Probably an error on in uv_guess_handle()
522 throw new Error('Implement me. Unknown stream file type!');
525 // For supporting legacy API we put the FD here.
528 stream._isStdio = true;
533 startup.processStdio = function() {
534 var stdin, stdout, stderr;
536 process.__defineGetter__('stdout', function() {
537 if (stdout) return stdout;
538 stdout = createWritableStdioStream(1);
539 stdout.destroy = stdout.destroySoon = function(er) {
540 er = er || new Error('process.stdout cannot be closed.');
541 stdout.emit('error', er);
544 process.on('SIGWINCH', function() {
545 stdout._refreshSize();
551 process.__defineGetter__('stderr', function() {
552 if (stderr) return stderr;
553 stderr = createWritableStdioStream(2);
554 stderr.destroy = stderr.destroySoon = function(er) {
555 er = er || new Error('process.stderr cannot be closed.');
556 stderr.emit('error', er);
561 process.__defineGetter__('stdin', function() {
562 if (stdin) return stdin;
564 var tty_wrap = process.binding('tty_wrap');
567 switch (tty_wrap.guessHandleType(fd)) {
569 var tty = NativeModule.require('tty');
570 stdin = new tty.ReadStream(fd, {
578 var fs = NativeModule.require('fs');
579 stdin = new fs.ReadStream(null, { fd: fd, autoClose: false });
584 var net = NativeModule.require('net');
586 // It could be that process has been started with an IPC channel
587 // sitting on fd=0, in such case the pipe for this fd is already
588 // present and creating a new one will lead to the assertion failure
590 if (process._channel && process._channel.fd === fd) {
591 stdin = new net.Socket({
592 handle: process._channel,
597 stdin = new net.Socket({
606 // Probably an error on in uv_guess_handle()
607 throw new Error('Implement me. Unknown stdin file type!');
610 // For supporting legacy API we put the FD here.
613 // stdin starts out life in a paused state, but node doesn't
614 // know yet. Explicitly to readStop() it to put it in the
615 // not-reading state.
616 if (stdin._handle && stdin._handle.readStop) {
617 stdin._handle.reading = false;
618 stdin._readableState.reading = false;
619 stdin._handle.readStop();
622 // if the user calls stdin.pause(), then we need to stop reading
623 // immediately, so that the process can close down.
624 stdin.on('pause', function() {
627 stdin._readableState.reading = false;
628 stdin._handle.reading = false;
629 stdin._handle.readStop();
635 process.openStdin = function() {
636 process.stdin.resume();
637 return process.stdin;
641 startup.processKillAndExit = function() {
643 process.exit = function(code) {
644 if (code || code === 0)
645 process.exitCode = code;
647 if (!process._exiting) {
648 process._exiting = true;
649 process.emit('exit', process.exitCode || 0);
651 process.reallyExit(process.exitCode || 0);
654 process.kill = function(pid, sig) {
657 if (typeof pid !== 'number' || !isFinite(pid)) {
658 throw new TypeError('pid must be a number');
661 // preserve null signal
663 err = process._kill(pid, 0);
665 sig = sig || 'SIGTERM';
666 if (startup.lazyConstants()[sig] &&
667 sig.slice(0, 3) === 'SIG') {
668 err = process._kill(pid, startup.lazyConstants()[sig]);
670 throw new Error('Unknown signal: ' + sig);
675 var errnoException = NativeModule.require('util')._errnoException;
676 throw errnoException(err, 'kill');
683 startup.processSignalHandlers = function() {
684 // Load events module in order to access prototype elements on process like
685 // process.addListener.
686 var signalWraps = {};
687 var addListener = process.addListener;
688 var removeListener = process.removeListener;
690 function isSignal(event) {
691 return event.slice(0, 3) === 'SIG' &&
692 startup.lazyConstants().hasOwnProperty(event);
695 // Wrap addListener for the special signal types
696 process.on = process.addListener = function(type, listener) {
697 if (isSignal(type) &&
698 !signalWraps.hasOwnProperty(type)) {
699 var Signal = process.binding('signal_wrap').Signal;
700 var wrap = new Signal();
704 wrap.onsignal = function() { process.emit(type); };
706 var signum = startup.lazyConstants()[type];
707 var err = wrap.start(signum);
710 var errnoException = NativeModule.require('util')._errnoException;
711 throw errnoException(err, 'uv_signal_start');
714 signalWraps[type] = wrap;
717 return addListener.apply(this, arguments);
720 process.removeListener = function(type, listener) {
721 var ret = removeListener.apply(this, arguments);
722 if (isSignal(type)) {
723 assert(signalWraps.hasOwnProperty(type));
725 if (NativeModule.require('events').listenerCount(this, type) === 0) {
726 signalWraps[type].close();
727 delete signalWraps[type];
736 startup.processChannel = function() {
737 // If we were spawned with env NODE_CHANNEL_FD then load that up and
738 // start parsing data from that stream.
739 if (process.env.NODE_CHANNEL_FD) {
740 var fd = parseInt(process.env.NODE_CHANNEL_FD, 10);
743 // Make sure it's not accidentally inherited by child processes.
744 delete process.env.NODE_CHANNEL_FD;
746 var cp = NativeModule.require('child_process');
748 // Load tcp_wrap to avoid situation where we might immediately receive
750 // FIXME is this really necessary?
751 process.binding('tcp_wrap');
754 assert(process.send);
759 startup.processRawDebug = function() {
760 var format = NativeModule.require('util').format;
761 var rawDebug = process._rawDebug;
762 process._rawDebug = function() {
763 rawDebug(format.apply(null, arguments));
768 startup.resolveArgv0 = function() {
769 var cwd = process.cwd();
770 var isWindows = process.platform === 'win32';
772 // Make process.argv[0] into a full path, but only touch argv[0] if it's
773 // not a system $PATH lookup.
774 // TODO: Make this work on Windows as well. Note that "node" might
775 // execute cwd\node.exe, or some %PATH%\node.exe on Windows,
776 // and that every directory has its own cwd, so d:node.exe is valid.
777 var argv0 = process.argv[0];
778 if (!isWindows && argv0.indexOf('/') !== -1 && argv0.charAt(0) !== '/') {
779 var path = NativeModule.require('path');
780 process.argv[0] = path.join(cwd, process.argv[0]);
784 // Below you find a minimal module system, which is used to load the node
785 // core modules found in lib/*.js. All core modules are compiled into the
786 // node binary, so they can be loaded faster.
788 var ContextifyScript = process.binding('contextify').ContextifyScript;
789 function runInThisContext(code, options) {
790 var script = new ContextifyScript(code, options);
791 return script.runInThisContext();
794 function NativeModule(id) {
795 this.filename = id + '.js';
801 NativeModule._source = process.binding('natives');
802 NativeModule._cache = {};
804 NativeModule.require = function(id) {
805 if (id == 'native_module') {
809 var cached = NativeModule.getCached(id);
811 return cached.exports;
814 if (!NativeModule.exists(id)) {
815 throw new Error('No such native module ' + id);
818 process.moduleLoadList.push('NativeModule ' + id);
820 var nativeModule = new NativeModule(id);
822 nativeModule.cache();
823 nativeModule.compile();
825 return nativeModule.exports;
828 NativeModule.getCached = function(id) {
829 return NativeModule._cache[id];
832 NativeModule.exists = function(id) {
833 return NativeModule._source.hasOwnProperty(id);
836 NativeModule.getSource = function(id) {
837 return NativeModule._source[id];
840 NativeModule.wrap = function(script) {
841 return NativeModule.wrapper[0] + script + NativeModule.wrapper[1];
844 NativeModule.wrapper = [
845 '(function (exports, require, module, __filename, __dirname) { ',
849 NativeModule.prototype.compile = function() {
850 var source = NativeModule.getSource(this.id);
851 source = NativeModule.wrap(source);
853 var fn = runInThisContext(source, { filename: this.filename });
854 fn(this.exports, NativeModule.require, this, this.filename);
859 NativeModule.prototype.cache = function() {
860 NativeModule._cache[this.id] = this;