diff --git a/doc/api/all.markdown b/doc/api/all.markdown index 5ccef037f5e1..2a164abb78e9 100644 --- a/doc/api/all.markdown +++ b/doc/api/all.markdown @@ -35,4 +35,3 @@ @include debugger @include cluster @include smalloc -@include tracing diff --git a/doc/api/tracing.markdown b/doc/api/tracing.markdown deleted file mode 100644 index 92e6809a04a0..000000000000 --- a/doc/api/tracing.markdown +++ /dev/null @@ -1,273 +0,0 @@ -# Tracing - - Stability: 1 - Experimental - -The tracing module is designed for instrumenting your Node application. It is -not meant for general purpose use. - -***Be very careful with callbacks used in conjunction with this module*** - -Many of these callbacks interact directly with asynchronous subsystems in a -synchronous fashion. That is to say, you may be in a callback where a call to -`console.log()` could result in an infinite recursive loop. Also of note, many -of these callbacks are in hot execution code paths. That is to say your -callbacks are executed quite often in the normal operation of Node, so be wary -of doing CPU bound or synchronous workloads in these functions. Consider a ring -buffer and a timer to defer processing. - -`require('tracing')` to use this module. - -## v8 - -The `v8` property is an [EventEmitter][], it exposes events and interfaces -specific to the version of `v8` built with node. These interfaces are subject -to change by upstream and are therefore not covered under the stability index. - -### Event: 'gc' - -`function (before, after) { }` - -Emitted each time a GC run is completed. - -`before` and `after` are objects with the following properties: - -``` -{ - type: 'mark-sweep-compact', - flags: 0, - timestamp: 905535650119053, - total_heap_size: 6295040, - total_heap_size_executable: 4194304, - total_physical_size: 6295040, - used_heap_size: 2855416, - heap_size_limit: 1535115264 -} -``` - -### getHeapStatistics() - -Returns an object with the following properties - -``` -{ - total_heap_size: 7326976, - total_heap_size_executable: 4194304, - total_physical_size: 7326976, - used_heap_size: 3476208, - heap_size_limit: 1535115264 -} -``` - - -# Async Listeners - -The `AsyncListener` API is the JavaScript interface for the `AsyncWrap` -class which allows developers to be notified about key events in the -lifetime of an asynchronous event. Node performs a lot of asynchronous -events internally, and significant use of this API may have a -**significant performance impact** on your application. - - -## tracing.createAsyncListener(callbacksObj[, userData]) - -* `callbacksObj` {Object} Contains optional callbacks that will fire at -specific times in the life cycle of the asynchronous event. -* `userData` {Value} a value that will be passed to all callbacks. - -Returns a constructed `AsyncListener` object. - -To begin capturing asynchronous events pass either the `callbacksObj` or -pass an existing `AsyncListener` instance to [`tracing.addAsyncListener()`][]. -The same `AsyncListener` instance can only be added once to the active -queue, and subsequent attempts to add the instance will be ignored. - -To stop capturing pass the `AsyncListener` instance to -[`tracing.removeAsyncListener()`][]. This does _not_ mean the -`AsyncListener` previously added will stop triggering callbacks. Once -attached to an asynchronous event it will persist with the lifetime of the -asynchronous call stack. - -Explanation of function parameters: - - -`callbacksObj`: An `Object` which may contain several optional fields: - -* `create(userData)`: A `Function` called when an asynchronous -event is instantiated. If a `Value` is returned then it will be attached -to the event and overwrite any value that had been passed to -`tracing.createAsyncListener()`'s `userData` argument. If an initial -`userData` was passed when created, then `create()` will -receive that as a function argument. - -* `before(context, userData)`: A `Function` that is called immediately -before the asynchronous callback is about to run. It will be passed both -the `context` (i.e. `this`) of the calling function and the `userData` -either returned from `create()` or passed during construction (if -either occurred). - -* `after(context, userData)`: A `Function` called immediately after -the asynchronous event's callback has run. Note this will not be called -if the callback throws and the error is not handled. - -* `error(userData, error)`: A `Function` called if the event's -callback threw. If this registered callback returns `true` then Node will -assume the error has been properly handled and resume execution normally. -When multiple `error()` callbacks have been registered only **one** of -those callbacks needs to return `true` for `AsyncListener` to accept that -the error has been handled, but all `error()` callbacks will always be run. - -`userData`: A `Value` (i.e. anything) that will be, by default, -attached to all new event instances. This will be overwritten if a `Value` -is returned by `create()`. - -Here is an example of overwriting the `userData`: - - tracing.createAsyncListener({ - create: function listener(value) { - // value === true - return false; - }, { - before: function before(context, value) { - // value === false - } - }, true); - -**Note:** The [EventEmitter][], while used to emit status of an asynchronous -event, is not itself asynchronous. So `create()` will not fire when -an event is added, and `before()`/`after()` will not fire when emitted -callbacks are called. - - -## tracing.addAsyncListener(callbacksObj[, userData]) -## tracing.addAsyncListener(asyncListener) - -Returns a constructed `AsyncListener` object and immediately adds it to -the listening queue to begin capturing asynchronous events. - -Function parameters can either be the same as -[`tracing.createAsyncListener()`][], or a constructed `AsyncListener` -object. - -Example usage for capturing errors: - - var fs = require('fs'); - - var cntr = 0; - var key = tracing.addAsyncListener({ - create: function onCreate() { - return { uid: cntr++ }; - }, - before: function onBefore(context, storage) { - // Write directly to stdout or we'll enter a recursive loop - fs.writeSync(1, 'uid: ' + storage.uid + ' is about to run\n'); - }, - after: function onAfter(context, storage) { - fs.writeSync(1, 'uid: ' + storage.uid + ' ran\n'); - }, - error: function onError(storage, err) { - // Handle known errors - if (err.message === 'everything is fine') { - // Writing to stderr this time. - fs.writeSync(2, 'handled error just threw:\n'); - fs.writeSync(2, err.stack + '\n'); - return true; - } - } - }); - - process.nextTick(function() { - throw new Error('everything is fine'); - }); - - // Output: - // uid: 0 is about to run - // handled error just threw: - // Error: really, it's ok - // at /tmp/test2.js:27:9 - // at process._tickCallback (node.js:583:11) - // at Function.Module.runMain (module.js:492:11) - // at startup (node.js:123:16) - // at node.js:1012:3 - -## tracing.removeAsyncListener(asyncListener) - -Removes the `AsyncListener` from the listening queue. - -Removing the `AsyncListener` from the active queue does _not_ mean the -`asyncListener` callbacks will cease to fire on the events they've been -registered. Subsequently, any asynchronous events fired during the -execution of a callback will also have the same `asyncListener` callbacks -attached for future execution. For example: - - var fs = require('fs'); - - var key = tracing.createAsyncListener({ - create: function asyncListener() { - // Write directly to stdout or we'll enter a recursive loop - fs.writeSync(1, 'You summoned me?\n'); - } - }); - - // We want to begin capturing async events some time in the future. - setTimeout(function() { - tracing.addAsyncListener(key); - - // Perform a few additional async events. - setTimeout(function() { - setImmediate(function() { - process.nextTick(function() { }); - }); - }); - - // Removing the listener doesn't mean to stop capturing events that - // have already been added. - tracing.removeAsyncListener(key); - }, 100); - - // Output: - // You summoned me? - // You summoned me? - // You summoned me? - // You summoned me? - -The fact that we logged 4 asynchronous events is an implementation detail -of Node's [Timers][]. - -To stop capturing from a specific asynchronous event stack -`tracing.removeAsyncListener()` must be called from within the call -stack itself. For example: - - var fs = require('fs'); - - var key = tracing.createAsyncListener({ - create: function asyncListener() { - // Write directly to stdout or we'll enter a recursive loop - fs.writeSync(1, 'You summoned me?\n'); - } - }); - - // We want to begin capturing async events some time in the future. - setTimeout(function() { - tracing.addAsyncListener(key); - - // Perform a few additional async events. - setImmediate(function() { - // Stop capturing from this call stack. - tracing.removeAsyncListener(key); - - process.nextTick(function() { }); - }); - }, 100); - - // Output: - // You summoned me? - -The user must be explicit and always pass the `AsyncListener` they wish -to remove. It is not possible to simply remove all listeners at once. - - -[EventEmitter]: events.html#events_class_events_eventemitter -[Timers]: timers.html -[`tracing.createAsyncListener()`]: #tracing_tracing_createasynclistener_asynclistener_callbacksobj_storagevalue -[`tracing.addAsyncListener()`]: #tracing_tracing_addasynclistener_asynclistener -[`tracing.removeAsyncListener()`]: #tracing_tracing_removeasynclistener_asynclistener diff --git a/lib/child_process.js b/lib/child_process.js index 4840c9e2bac5..c4345f90c2ab 100644 --- a/lib/child_process.js +++ b/lib/child_process.js @@ -27,6 +27,7 @@ var assert = require('assert'); var util = require('util'); var Process = process.binding('process_wrap').Process; +var WriteWrap = process.binding('stream_wrap').WriteWrap; var uv = process.binding('uv'); var spawn_sync; // Lazy-loaded process.binding('spawn_sync') @@ -473,7 +474,8 @@ function setupChannel(target, channel) { return; } - var req = { oncomplete: nop }; + var req = new WriteWrap(); + req.oncomplete = nop; var string = JSON.stringify(message) + '\n'; var err = channel.writeUtf8String(req, string, handle); diff --git a/lib/dgram.js b/lib/dgram.js index aae2f51bc86b..d1bfa14caa07 100644 --- a/lib/dgram.js +++ b/lib/dgram.js @@ -25,6 +25,7 @@ var events = require('events'); var constants = require('constants'); var UDP = process.binding('udp_wrap').UDP; +var SendWrap = process.binding('udp_wrap').SendWrap; var BIND_STATE_UNBOUND = 0; var BIND_STATE_BINDING = 1; @@ -317,7 +318,9 @@ Socket.prototype.send = function(buffer, self.emit('error', ex); } else if (self._handle) { - var req = { buffer: buffer, length: length }; // Keep reference alive. + var req = new SendWrap(); + req.buffer = buffer; // Keep reference alive. + req.length = length; if (callback) { req.callback = callback; req.oncomplete = afterSend; diff --git a/lib/dns.js b/lib/dns.js index 4eb34d6651b1..18023fab1621 100644 --- a/lib/dns.js +++ b/lib/dns.js @@ -25,6 +25,9 @@ var util = require('util'); var cares = process.binding('cares_wrap'); var uv = process.binding('uv'); +var GetAddrInfoReqWrap = cares.GetAddrInfoReqWrap; +var GetNameInfoReqWrap = cares.GetNameInfoReqWrap; + var isIp = net.isIP; @@ -142,12 +145,11 @@ exports.lookup = function lookup(hostname, options, callback) { return {}; } - var req = { - callback: callback, - family: family, - hostname: hostname, - oncomplete: onlookup - }; + var req = new GetAddrInfoReqWrap(); + req.callback = callback; + req.family = family; + req.hostname = hostname; + req.oncomplete = onlookup; var err = cares.getaddrinfo(req, hostname, family, hints); if (err) { @@ -178,12 +180,12 @@ exports.lookupService = function(host, port, callback) { callback = makeAsync(callback); - var req = { - callback: callback, - host: host, - port: port, - oncomplete: onlookupservice - }; + var req = new GetNameInfoReqWrap(); + req.callback = callback; + req.host = host; + req.port = port; + req.oncomplete = onlookupservice; + var err = cares.getnameinfo(req, host, port); if (err) throw errnoException(err, 'getnameinfo', host); diff --git a/lib/fs.js b/lib/fs.js index 3301a6af8474..a97ba3aa639b 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -33,6 +33,7 @@ var constants = process.binding('constants'); var fs = exports; var Stream = require('stream').Stream; var EventEmitter = require('events').EventEmitter; +var FSReqWrap = binding.FSReqWrap; var Readable = Stream.Readable; var Writable = Stream.Writable; @@ -182,7 +183,9 @@ fs.Stats.prototype.isSocket = function() { fs.exists = function(path, callback) { if (!nullCheck(path, cb)) return; - binding.stat(pathModule._makeLong(path), cb); + var req = new FSReqWrap(); + req.oncomplete = cb; + binding.stat(pathModule._makeLong(path), req); function cb(err, stats) { if (callback) callback(err ? false : true); } @@ -421,7 +424,9 @@ Object.defineProperty(exports, '_stringToFlags', { // list to make the arguments clear. fs.close = function(fd, callback) { - binding.close(fd, makeCallback(callback)); + var req = new FSReqWrap(); + req.oncomplete = makeCallback(callback); + binding.close(fd, req); }; fs.closeSync = function(fd) { @@ -443,10 +448,14 @@ fs.open = function(path, flags, mode, callback) { mode = modeNum(mode, 438 /*=0666*/); if (!nullCheck(path, callback)) return; + + var req = new FSReqWrap(); + req.oncomplete = callback; + binding.open(pathModule._makeLong(path), stringToFlags(flags), mode, - callback); + req); }; fs.openSync = function(path, flags, mode) { @@ -482,7 +491,10 @@ fs.read = function(fd, buffer, offset, length, position, callback) { callback && callback(err, bytesRead || 0, buffer); } - binding.read(fd, buffer, offset, length, position, wrapper); + var req = new FSReqWrap(); + req.oncomplete = wrapper; + + binding.read(fd, buffer, offset, length, position, req); }; fs.readSync = function(fd, buffer, offset, length, position) { @@ -515,6 +527,16 @@ fs.readSync = function(fd, buffer, offset, length, position) { // OR // fs.write(fd, string[, position[, encoding]], callback); fs.write = function(fd, buffer, offset, length, position, callback) { + function strWrapper(err, written) { + // Retain a reference to buffer so that it can't be GC'ed too soon. + callback(err, written || 0, buffer); + } + + function bufWrapper(err, written) { + // retain reference to string in case it's external + callback(err, written || 0, buffer); + } + if (util.isBuffer(buffer)) { // if no position is passed then assume null if (util.isFunction(position)) { @@ -522,11 +544,9 @@ fs.write = function(fd, buffer, offset, length, position, callback) { position = null; } callback = maybeCallback(callback); - var wrapper = function(err, written) { - // Retain a reference to buffer so that it can't be GC'ed too soon. - callback(err, written || 0, buffer); - }; - return binding.writeBuffer(fd, buffer, offset, length, position, wrapper); + var req = new FSReqWrap(); + req.oncomplete = strWrapper; + return binding.writeBuffer(fd, buffer, offset, length, position, req); } if (util.isString(buffer)) @@ -541,11 +561,9 @@ fs.write = function(fd, buffer, offset, length, position, callback) { length = 'utf8'; } callback = maybeCallback(position); - position = function(err, written) { - // retain reference to string in case it's external - callback(err, written || 0, buffer); - }; - return binding.writeString(fd, buffer, offset, length, position); + var req = new FSReqWrap(); + req.oncomplete = bufWrapper; + return binding.writeString(fd, buffer, offset, length, req); }; // usage: @@ -569,9 +587,11 @@ fs.rename = function(oldPath, newPath, callback) { callback = makeCallback(callback); if (!nullCheck(oldPath, callback)) return; if (!nullCheck(newPath, callback)) return; + var req = new FSReqWrap(); + req.oncomplete = callback; binding.rename(pathModule._makeLong(oldPath), pathModule._makeLong(newPath), - callback); + req); }; fs.renameSync = function(oldPath, newPath) { @@ -583,8 +603,9 @@ fs.renameSync = function(oldPath, newPath) { fs.truncate = function(path, len, callback) { if (util.isNumber(path)) { - // legacy - return fs.ftruncate(path, len, callback); + var req = new FSReqWrap(); + req.oncomplete = callback; + return fs.ftruncate(path, len, req); } if (util.isFunction(len)) { callback = len; @@ -592,14 +613,17 @@ fs.truncate = function(path, len, callback) { } else if (util.isUndefined(len)) { len = 0; } + callback = maybeCallback(callback); fs.open(path, 'r+', function(er, fd) { if (er) return callback(er); - binding.ftruncate(fd, len, function(er) { + var req = new FSReqWrap(); + req.oncomplete = function ftruncateCb(er) { fs.close(fd, function(er2) { callback(er || er2); }); - }); + }; + binding.ftruncate(fd, len, req); }); }; @@ -628,7 +652,9 @@ fs.ftruncate = function(fd, len, callback) { } else if (util.isUndefined(len)) { len = 0; } - binding.ftruncate(fd, len, makeCallback(callback)); + var req = new FSReqWrap(); + req.oncomplete = makeCallback(callback); + binding.ftruncate(fd, len, req); }; fs.ftruncateSync = function(fd, len) { @@ -639,9 +665,11 @@ fs.ftruncateSync = function(fd, len) { }; fs.rmdir = function(path, callback) { - callback = makeCallback(callback); + callback = maybeCallback(callback); if (!nullCheck(path, callback)) return; - binding.rmdir(pathModule._makeLong(path), callback); + var req = new FSReqWrap(); + req.oncomplete = callback; + binding.rmdir(pathModule._makeLong(path), req); }; fs.rmdirSync = function(path) { @@ -650,7 +678,9 @@ fs.rmdirSync = function(path) { }; fs.fdatasync = function(fd, callback) { - binding.fdatasync(fd, makeCallback(callback)); + var req = new FSReqWrap(); + req.oncomplete = makeCallback(callback); + binding.fdatasync(fd, req); }; fs.fdatasyncSync = function(fd) { @@ -658,7 +688,9 @@ fs.fdatasyncSync = function(fd) { }; fs.fsync = function(fd, callback) { - binding.fsync(fd, makeCallback(callback)); + var req = new FSReqWrap(); + req.oncomplete = makeCallback(callback); + binding.fsync(fd, req); }; fs.fsyncSync = function(fd) { @@ -669,9 +701,11 @@ fs.mkdir = function(path, mode, callback) { if (util.isFunction(mode)) callback = mode; callback = makeCallback(callback); if (!nullCheck(path, callback)) return; + var req = new FSReqWrap(); + req.oncomplete = callback; binding.mkdir(pathModule._makeLong(path), modeNum(mode, 511 /*=0777*/), - callback); + req); }; fs.mkdirSync = function(path, mode) { @@ -683,7 +717,9 @@ fs.mkdirSync = function(path, mode) { fs.readdir = function(path, callback) { callback = makeCallback(callback); if (!nullCheck(path, callback)) return; - binding.readdir(pathModule._makeLong(path), callback); + var req = new FSReqWrap(); + req.oncomplete = callback; + binding.readdir(pathModule._makeLong(path), req); }; fs.readdirSync = function(path) { @@ -692,19 +728,25 @@ fs.readdirSync = function(path) { }; fs.fstat = function(fd, callback) { - binding.fstat(fd, makeCallback(callback)); + var req = new FSReqWrap(); + req.oncomplete = makeCallback(callback); + binding.fstat(fd, req); }; fs.lstat = function(path, callback) { callback = makeCallback(callback); if (!nullCheck(path, callback)) return; - binding.lstat(pathModule._makeLong(path), callback); + var req = new FSReqWrap(); + req.oncomplete = callback; + binding.lstat(pathModule._makeLong(path), req); }; fs.stat = function(path, callback) { callback = makeCallback(callback); if (!nullCheck(path, callback)) return; - binding.stat(pathModule._makeLong(path), callback); + var req = new FSReqWrap(); + req.oncomplete = callback; + binding.stat(pathModule._makeLong(path), req); }; fs.fstatSync = function(fd) { @@ -724,7 +766,9 @@ fs.statSync = function(path) { fs.readlink = function(path, callback) { callback = makeCallback(callback); if (!nullCheck(path, callback)) return; - binding.readlink(pathModule._makeLong(path), callback); + var req = new FSReqWrap(); + req.oncomplete = callback; + binding.readlink(pathModule._makeLong(path), req); }; fs.readlinkSync = function(path) { @@ -752,10 +796,13 @@ fs.symlink = function(destination, path, type_, callback) { if (!nullCheck(destination, callback)) return; if (!nullCheck(path, callback)) return; + var req = new FSReqWrap(); + req.oncomplete = callback; + binding.symlink(preprocessSymlinkDestination(destination, type), pathModule._makeLong(path), type, - callback); + req); }; fs.symlinkSync = function(destination, path, type) { @@ -774,9 +821,12 @@ fs.link = function(srcpath, dstpath, callback) { if (!nullCheck(srcpath, callback)) return; if (!nullCheck(dstpath, callback)) return; + var req = new FSReqWrap(); + req.oncomplete = callback; + binding.link(pathModule._makeLong(srcpath), pathModule._makeLong(dstpath), - callback); + req); }; fs.linkSync = function(srcpath, dstpath) { @@ -789,7 +839,9 @@ fs.linkSync = function(srcpath, dstpath) { fs.unlink = function(path, callback) { callback = makeCallback(callback); if (!nullCheck(path, callback)) return; - binding.unlink(pathModule._makeLong(path), callback); + var req = new FSReqWrap(); + req.oncomplete = callback; + binding.unlink(pathModule._makeLong(path), req); }; fs.unlinkSync = function(path) { @@ -798,7 +850,9 @@ fs.unlinkSync = function(path) { }; fs.fchmod = function(fd, mode, callback) { - binding.fchmod(fd, modeNum(mode), makeCallback(callback)); + var req = new FSReqWrap(); + req.oncomplete = makeCallback(callback); + binding.fchmod(fd, modeNum(mode), req); }; fs.fchmodSync = function(fd, mode) { @@ -848,9 +902,11 @@ if (constants.hasOwnProperty('O_SYMLINK')) { fs.chmod = function(path, mode, callback) { callback = makeCallback(callback); if (!nullCheck(path, callback)) return; + var req = new FSReqWrap(); + req.oncomplete = callback; binding.chmod(pathModule._makeLong(path), modeNum(mode), - callback); + req); }; fs.chmodSync = function(path, mode) { @@ -877,7 +933,9 @@ if (constants.hasOwnProperty('O_SYMLINK')) { } fs.fchown = function(fd, uid, gid, callback) { - binding.fchown(fd, uid, gid, makeCallback(callback)); + var req = new FSReqWrap(); + req.oncomplete = makeCallback(callback); + binding.fchown(fd, uid, gid, req); }; fs.fchownSync = function(fd, uid, gid) { @@ -887,7 +945,9 @@ fs.fchownSync = function(fd, uid, gid) { fs.chown = function(path, uid, gid, callback) { callback = makeCallback(callback); if (!nullCheck(path, callback)) return; - binding.chown(pathModule._makeLong(path), uid, gid, callback); + var req = new FSReqWrap(); + req.oncomplete = callback; + binding.chown(pathModule._makeLong(path), uid, gid, req); }; fs.chownSync = function(path, uid, gid) { @@ -913,10 +973,12 @@ fs._toUnixTimestamp = toUnixTimestamp; fs.utimes = function(path, atime, mtime, callback) { callback = makeCallback(callback); if (!nullCheck(path, callback)) return; + var req = new FSReqWrap(); + req.oncomplete = callback; binding.utimes(pathModule._makeLong(path), toUnixTimestamp(atime), toUnixTimestamp(mtime), - callback); + req); }; fs.utimesSync = function(path, atime, mtime) { @@ -929,7 +991,9 @@ fs.utimesSync = function(path, atime, mtime) { fs.futimes = function(fd, atime, mtime, callback) { atime = toUnixTimestamp(atime); mtime = toUnixTimestamp(mtime); - binding.futimes(fd, atime, mtime, makeCallback(callback)); + var req = new FSReqWrap(); + req.oncomplete = makeCallback(callback); + binding.futimes(fd, atime, mtime, req); }; fs.futimesSync = function(fd, atime, mtime) { diff --git a/lib/net.js b/lib/net.js index 34de98bc3c01..fac78f8c04dc 100644 --- a/lib/net.js +++ b/lib/net.js @@ -28,6 +28,11 @@ var cares = process.binding('cares_wrap'); var uv = process.binding('uv'); var Pipe = process.binding('pipe_wrap').Pipe; +var TCPConnectWrap = process.binding('tcp_wrap').TCPConnectWrap; +var PipeConnectWrap = process.binding('pipe_wrap').PipeConnectWrap; +var ShutdownWrap = process.binding('stream_wrap').ShutdownWrap; +var WriteWrap = process.binding('stream_wrap').WriteWrap; + var cluster; var errnoException = util._errnoException; @@ -218,7 +223,8 @@ function onSocketFinish() { if (!this._handle || !this._handle.shutdown) return this.destroy(); - var req = { oncomplete: afterShutdown }; + var req = new ShutdownWrap(); + req.oncomplete = afterShutdown; var err = this._handle.shutdown(req); if (err) @@ -641,7 +647,9 @@ Socket.prototype._writeGeneric = function(writev, data, encoding, cb) { return false; } - var req = { oncomplete: afterWrite, async: false }; + var req = new WriteWrap(); + req.oncomplete = afterWrite; + req.async = false; var err; if (writev) { @@ -821,8 +829,9 @@ function connect(self, address, port, addressType, localAddress, localPort) { } } - var req = { oncomplete: afterConnect }; if (addressType === 6 || addressType === 4) { + var req = new TCPConnectWrap(); + req.oncomplete = afterConnect; port = port | 0; if (port <= 0 || port > 65535) throw new RangeError('Port should be > 0 and < 65536'); @@ -833,6 +842,8 @@ function connect(self, address, port, addressType, localAddress, localPort) { err = self._handle.connect(req, address, port); } } else { + var req = new PipeConnectWrap(); + req.oncomplete = afterConnect; err = self._handle.connect(req, address, afterConnect); } diff --git a/lib/repl.js b/lib/repl.js index 578f99ed2257..a8fa060c5930 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -72,8 +72,7 @@ exports.writer = util.inspect; exports._builtinLibs = ['assert', 'buffer', 'child_process', 'cluster', 'crypto', 'dgram', 'dns', 'domain', 'events', 'fs', 'http', 'https', 'net', 'os', 'path', 'punycode', 'querystring', 'readline', 'stream', - 'string_decoder', 'tls', 'tty', 'url', 'util', 'vm', 'zlib', 'smalloc', - 'tracing']; + 'string_decoder', 'tls', 'tty', 'url', 'util', 'vm', 'zlib', 'smalloc']; function REPLServer(prompt, stream, eval_, useGlobal, ignoreUndefined) { diff --git a/lib/timers.js b/lib/timers.js index 3039b49f2c37..68e3e65e9aaf 100644 --- a/lib/timers.js +++ b/lib/timers.js @@ -30,21 +30,6 @@ var TIMEOUT_MAX = 2147483647; // 2^31-1 var debug = require('util').debuglog('timer'); -var tracing = require('tracing'); -var asyncFlags = tracing._asyncFlags; -var runAsyncQueue = tracing._runAsyncQueue; -var loadAsyncQueue = tracing._loadAsyncQueue; -var unloadAsyncQueue = tracing._unloadAsyncQueue; - -// Same as in AsyncListener in env.h -var kHasListener = 0; - -// Do a little housekeeping. -delete tracing._asyncFlags; -delete tracing._runAsyncQueue; -delete tracing._loadAsyncQueue; -delete tracing._unloadAsyncQueue; - // IDLE TIMEOUTS // @@ -59,11 +44,6 @@ delete tracing._unloadAsyncQueue; // value = list var lists = {}; -// Make Timer as monomorphic as possible. -Timer.prototype._asyncQueue = undefined; -Timer.prototype._asyncData = undefined; -Timer.prototype._asyncFlags = 0; - // the main function - creates lists on demand and the watchers associated // with them. function insert(item, msecs) { @@ -100,7 +80,7 @@ function listOnTimeout() { var now = Timer.now(); debug('now: %s', now); - var diff, first, hasQueue, threw; + var diff, first, threw; while (first = L.peek(list)) { diff = now - first._idleStart; if (diff < msecs) { @@ -122,19 +102,13 @@ function listOnTimeout() { if (domain && domain._disposed) continue; - hasQueue = !!first._asyncQueue; - try { - if (hasQueue) - loadAsyncQueue(first); if (domain) domain.enter(); threw = true; first._onTimeout(); if (domain) domain.exit(); - if (hasQueue) - unloadAsyncQueue(first); threw = false; } finally { if (threw) { @@ -204,11 +178,6 @@ exports.active = function(item) { L.append(list, item); } } - // Whether or not a new TimerWrap needed to be created, this should run - // for each item. This way each "item" (i.e. timer) can properly have - // their own domain assigned. - if (asyncFlags[kHasListener] > 0) - runAsyncQueue(item); }; @@ -354,18 +323,15 @@ L.init(immediateQueue); function processImmediate() { var queue = immediateQueue; - var domain, hasQueue, immediate; + var domain, immediate; immediateQueue = {}; L.init(immediateQueue); while (L.isEmpty(queue) === false) { immediate = L.shift(queue); - hasQueue = !!immediate._asyncQueue; domain = immediate.domain; - if (hasQueue) - loadAsyncQueue(immediate); if (domain) domain.enter(); @@ -389,8 +355,6 @@ function processImmediate() { if (domain) domain.exit(); - if (hasQueue) - unloadAsyncQueue(immediate); } // Only round-trip to C++ land if we have to. Calling clearImmediate() on an @@ -406,11 +370,8 @@ function Immediate() { } Immediate.prototype.domain = undefined; Immediate.prototype._onImmediate = undefined; -Immediate.prototype._asyncQueue = undefined; -Immediate.prototype._asyncData = undefined; Immediate.prototype._idleNext = undefined; Immediate.prototype._idlePrev = undefined; -Immediate.prototype._asyncFlags = 0; exports.setImmediate = function(callback) { @@ -436,9 +397,6 @@ exports.setImmediate = function(callback) { process._immediateCallback = processImmediate; } - // setImmediates are handled more like nextTicks. - if (asyncFlags[kHasListener] > 0) - runAsyncQueue(immediate); if (process.domain) immediate.domain = process.domain; @@ -472,7 +430,7 @@ function unrefTimeout() { debug('unrefTimer fired'); - var diff, domain, first, hasQueue, threw; + var diff, domain, first, threw; while (first = L.peek(unrefList)) { diff = now - first._idleStart; @@ -490,11 +448,8 @@ function unrefTimeout() { if (!first._onTimeout) continue; if (domain && domain._disposed) continue; - hasQueue = !!first._asyncQueue; try { - if (hasQueue) - loadAsyncQueue(first); if (domain) domain.enter(); threw = true; debug('unreftimer firing timeout'); @@ -502,8 +457,6 @@ function unrefTimeout() { threw = false; if (domain) domain.exit(); - if (hasQueue) - unloadAsyncQueue(first); } finally { if (threw) process.nextTick(unrefTimeout); } diff --git a/lib/tracing.js b/lib/tracing.js deleted file mode 100644 index 49d0dec35c28..000000000000 --- a/lib/tracing.js +++ /dev/null @@ -1,395 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var EventEmitter = require('events'); -var v8binding, process; - -// This needs to be loaded early, and before the "process" object is made -// global. So allow src/node.js to pass the process object in during -// initialization. -exports._nodeInitialization = function nodeInitialization(pobj) { - process = pobj; - v8binding = process.binding('v8'); - - // Finish setting up the v8 Object. - v8.getHeapStatistics = v8binding.getHeapStatistics; - - // Part of the AsyncListener setup to share objects/callbacks with the - // native layer. - process._setupAsyncListener(asyncFlags, - runAsyncQueue, - loadAsyncQueue, - unloadAsyncQueue); - - // Do a little housekeeping. - delete exports._nodeInitialization; -}; - - -// v8 - -var v8 = exports.v8 = new EventEmitter(); - - -function emitGC(before, after) { - v8.emit('gc', before, after); -} - - -v8.on('newListener', function(name) { - if (name === 'gc' && EventEmitter.listenerCount(this, name) === 0) { - v8binding.startGarbageCollectionTracking(emitGC); - } -}); - - -v8.on('removeListener', function(name) { - if (name === 'gc' && EventEmitter.listenerCount(this, name) === 0) { - v8binding.stopGarbageCollectionTracking(); - } -}); - - -// AsyncListener - -// new Array() is used here because it is more efficient for sparse -// arrays. Please *do not* change these to simple bracket notation. - -// Track the active queue of AsyncListeners that have been added. -var asyncQueue = new Array(); - -// Keep the stack of all contexts that have been loaded in the -// execution chain of asynchronous events. -var contextStack = new Array(); -var currentContext = undefined; - -// Incremental uid for new AsyncListener instances. -var alUid = 0; - -// Stateful flags shared with Environment for quick JS/C++ -// communication. -var asyncFlags = {}; - -// Prevent accidentally suppressed thrown errors from before/after. -var inAsyncTick = false; - -// To prevent infinite recursion when an error handler also throws -// flag when an error is currenly being handled. -var inErrorTick = false; - -// Needs to be the same as src/env.h -var kHasListener = 0; - -// Flags to determine what async listeners are available. -var HAS_CREATE_AL = 1 << 0; -var HAS_BEFORE_AL = 1 << 1; -var HAS_AFTER_AL = 1 << 2; -var HAS_ERROR_AL = 1 << 3; - -// _errorHandler is scoped so it's also accessible by _fatalException. -exports._errorHandler = errorHandler; - -// Needs to be accessible from lib/timers.js so they know when async -// listeners are currently in queue. They'll be cleaned up once -// references there are made. -exports._asyncFlags = asyncFlags; -exports._runAsyncQueue = runAsyncQueue; -exports._loadAsyncQueue = loadAsyncQueue; -exports._unloadAsyncQueue = unloadAsyncQueue; - -// Public API. -exports.createAsyncListener = createAsyncListener; -exports.addAsyncListener = addAsyncListener; -exports.removeAsyncListener = removeAsyncListener; - -// Load the currently executing context as the current context, and -// create a new asyncQueue that can receive any added queue items -// during the executing of the callback. -function loadContext(ctx) { - contextStack.push(currentContext); - currentContext = ctx; - - asyncFlags[kHasListener] = 1; -} - -function unloadContext() { - currentContext = contextStack.pop(); - - if (currentContext === undefined && asyncQueue.length === 0) - asyncFlags[kHasListener] = 0; -} - -// Run all the async listeners attached when an asynchronous event is -// instantiated. -function runAsyncQueue(context) { - var queue = new Array(); - var data = new Array(); - var ccQueue, i, queueItem, value; - - context._asyncQueue = queue; - context._asyncData = data; - context._asyncFlags = 0; - - inAsyncTick = true; - - // First run through all callbacks in the currentContext. These may - // add new AsyncListeners to the asyncQueue during execution. Hence - // why they need to be evaluated first. - if (currentContext) { - ccQueue = currentContext._asyncQueue; - context._asyncFlags |= currentContext._asyncFlags; - for (i = 0; i < ccQueue.length; i++) { - queueItem = ccQueue[i]; - queue[queue.length] = queueItem; - if ((queueItem.callback_flags & HAS_CREATE_AL) === 0) { - data[queueItem.uid] = queueItem.data; - continue; - } - value = queueItem.create(queueItem.data); - data[queueItem.uid] = (value === undefined) ? queueItem.data : value; - } - } - - // Then run through all items in the asyncQueue - if (asyncQueue) { - for (i = 0; i < asyncQueue.length; i++) { - queueItem = asyncQueue[i]; - // Quick way to check if an AL instance with the same uid was - // already run from currentContext. - if (data[queueItem.uid] !== undefined) - continue; - queue[queue.length] = queueItem; - context._asyncFlags |= queueItem.callback_flags; - if ((queueItem.callback_flags & HAS_CREATE_AL) === 0) { - data[queueItem.uid] = queueItem.data; - continue; - } - value = queueItem.create(queueItem.data); - data[queueItem.uid] = (value === undefined) ? queueItem.data : value; - } - } - - inAsyncTick = false; -} - -// Load the AsyncListener queue attached to context and run all -// "before" callbacks, if they exist. -function loadAsyncQueue(context) { - loadContext(context); - - if ((context._asyncFlags & HAS_BEFORE_AL) === 0) - return; - - var queue = context._asyncQueue; - var data = context._asyncData; - var i, queueItem; - - inAsyncTick = true; - for (i = 0; i < queue.length; i++) { - queueItem = queue[i]; - if ((queueItem.callback_flags & HAS_BEFORE_AL) > 0) - queueItem.before(context, data[queueItem.uid]); - } - inAsyncTick = false; -} - -// Unload the AsyncListener queue attached to context and run all -// "after" callbacks, if they exist. -function unloadAsyncQueue(context) { - if ((context._asyncFlags & HAS_AFTER_AL) === 0) { - unloadContext(); - return; - } - - var queue = context._asyncQueue; - var data = context._asyncData; - var i, queueItem; - - inAsyncTick = true; - for (i = 0; i < queue.length; i++) { - queueItem = queue[i]; - if ((queueItem.callback_flags & HAS_AFTER_AL) > 0) - queueItem.after(context, data[queueItem.uid]); - } - inAsyncTick = false; - - unloadContext(); -} - -// Handle errors that are thrown while in the context of an -// AsyncListener. If an error is thrown from an AsyncListener -// callback error handlers will be called once more to report -// the error, then the application will die forcefully. -function errorHandler(er) { - if (inErrorTick) - return false; - - var handled = false; - var i, queueItem, threw; - - inErrorTick = true; - - // First process error callbacks from the current context. - if (currentContext && (currentContext._asyncFlags & HAS_ERROR_AL) > 0) { - var queue = currentContext._asyncQueue; - var data = currentContext._asyncData; - for (i = 0; i < queue.length; i++) { - queueItem = queue[i]; - if ((queueItem.callback_flags & HAS_ERROR_AL) === 0) - continue; - try { - threw = true; - // While it would be possible to pass in currentContext, if - // the error is thrown from the "create" callback then there's - // a chance the object hasn't been fully constructed. - handled = queueItem.error(data[queueItem.uid], er) || handled; - threw = false; - } finally { - // If the error callback thew then die quickly. Only allow the - // exit events to be processed. - if (threw) { - process._exiting = true; - process.emit('exit', 1); - } - } - } - } - - // Now process callbacks from any existing queue. - if (asyncQueue) { - for (i = 0; i < asyncQueue.length; i++) { - queueItem = asyncQueue[i]; - if ((queueItem.callback_flags & HAS_ERROR_AL) === 0 || - (data && data[queueItem.uid] !== undefined)) - continue; - try { - threw = true; - handled = queueItem.error(queueItem.data, er) || handled; - threw = false; - } finally { - // If the error callback thew then die quickly. Only allow the - // exit events to be processed. - if (threw) { - process._exiting = true; - process.emit('exit', 1); - } - } - } - } - - inErrorTick = false; - - unloadContext(); - - // TODO(trevnorris): If the error was handled, should the after callbacks - // be fired anyways? - - return handled && !inAsyncTick; -} - -// Instance function of an AsyncListener object. -function AsyncListenerInst(callbacks, data) { - if (typeof callbacks.create === 'function') { - this.create = callbacks.create; - this.callback_flags |= HAS_CREATE_AL; - } - if (typeof callbacks.before === 'function') { - this.before = callbacks.before; - this.callback_flags |= HAS_BEFORE_AL; - } - if (typeof callbacks.after === 'function') { - this.after = callbacks.after; - this.callback_flags |= HAS_AFTER_AL; - } - if (typeof callbacks.error === 'function') { - this.error = callbacks.error; - this.callback_flags |= HAS_ERROR_AL; - } - - this.uid = ++alUid; - this.data = data === undefined ? null : data; -} -AsyncListenerInst.prototype.create = undefined; -AsyncListenerInst.prototype.before = undefined; -AsyncListenerInst.prototype.after = undefined; -AsyncListenerInst.prototype.error = undefined; -AsyncListenerInst.prototype.data = undefined; -AsyncListenerInst.prototype.uid = 0; -AsyncListenerInst.prototype.callback_flags = 0; - -// Create new async listener object. Useful when instantiating a new -// object and want the listener instance, but not add it to the stack. -// If an existing AsyncListenerInst is passed then any new "data" is -// ignored. -function createAsyncListener(callbacks, data) { - if (typeof callbacks !== 'object' || callbacks == null) - throw new TypeError('callbacks argument must be an object'); - - if (callbacks instanceof AsyncListenerInst) - return callbacks; - else - return new AsyncListenerInst(callbacks, data); -} - -// Add a listener to the current queue. -function addAsyncListener(callbacks, data) { - // Fast track if a new AsyncListenerInst has to be created. - if (!(callbacks instanceof AsyncListenerInst)) { - callbacks = createAsyncListener(callbacks, data); - asyncQueue.push(callbacks); - asyncFlags[kHasListener] = 1; - return callbacks; - } - - var inQueue = false; - // The asyncQueue will be small. Probably always <= 3 items. - for (var i = 0; i < asyncQueue.length; i++) { - if (callbacks === asyncQueue[i]) { - inQueue = true; - break; - } - } - - // Make sure the callback doesn't already exist in the queue. - if (!inQueue) { - asyncQueue.push(callbacks); - asyncFlags[kHasListener] = 1; - } - - return callbacks; -} - -// Remove listener from the current queue. Though this will not remove -// the listener from the current context. So callback propagation will -// continue. -function removeAsyncListener(obj) { - for (var i = 0; i < asyncQueue.length; i++) { - if (obj === asyncQueue[i]) { - asyncQueue.splice(i, 1); - break; - } - } - - if (asyncQueue.length > 0 || currentContext !== undefined) - asyncFlags[kHasListener] = 1; - else - asyncFlags[kHasListener] = 0; -} diff --git a/node.gyp b/node.gyp index daf06c7a7a0f..1ed8d673eeca 100644 --- a/node.gyp +++ b/node.gyp @@ -57,7 +57,6 @@ 'lib/string_decoder.js', 'lib/sys.js', 'lib/timers.js', - 'lib/tracing.js', 'lib/tls.js', 'lib/_tls_common.js', 'lib/_tls_legacy.js', @@ -89,6 +88,7 @@ ], 'sources': [ + 'src/async-wrap.cc', 'src/fs_event_wrap.cc', 'src/cares_wrap.cc', 'src/handle_wrap.cc', diff --git a/src/async-wrap-inl.h b/src/async-wrap-inl.h index 59157cc0f4c6..f064ea96cf44 100644 --- a/src/async-wrap-inl.h +++ b/src/async-wrap-inl.h @@ -27,205 +27,64 @@ #include "base-object-inl.h" #include "env.h" #include "env-inl.h" +#include "node_internals.h" #include "util.h" #include "util-inl.h" #include "v8.h" -#include namespace node { inline AsyncWrap::AsyncWrap(Environment* env, v8::Handle object, - ProviderType provider) + ProviderType provider, + AsyncWrap* parent) : BaseObject(env, object), - async_flags_(NO_OPTIONS), + has_async_queue_(false), provider_type_(provider) { - if (!env->has_async_listener()) + // Check user controlled flag to see if the init callback should run. + if (!env->call_async_init_hook()) return; - // TODO(trevnorris): Do we really need to TryCatch this call? - v8::TryCatch try_catch; - try_catch.SetVerbose(true); - - v8::Local val = object.As(); - env->async_listener_run_function()->Call(env->process_object(), 1, &val); - - if (!try_catch.HasCaught()) - async_flags_ |= HAS_ASYNC_LISTENER; -} - - -inline AsyncWrap::~AsyncWrap() { -} - -inline uint32_t AsyncWrap::provider_type() const { - return provider_type_; -} - - -inline bool AsyncWrap::has_async_listener() { - return async_flags_ & HAS_ASYNC_LISTENER; -} - - -// I hate you domains. -inline v8::Handle AsyncWrap::MakeDomainCallback( - const v8::Handle cb, - int argc, - v8::Handle* argv) { - assert(env()->context() == env()->isolate()->GetCurrentContext()); + // TODO(trevnorris): Until it's verified all passed object's are not weak, + // add a HandleScope to make sure there's no leak. + v8::HandleScope scope(env->isolate()); - v8::Local context = object(); - v8::Local process = env()->process_object(); - v8::Local domain_v = context->Get(env()->domain_string()); - v8::Local domain; + v8::Local parent_obj; v8::TryCatch try_catch; - try_catch.SetVerbose(true); - - if (has_async_listener()) { - v8::Local val = context.As(); - env()->async_listener_load_function()->Call(process, 1, &val); + // If a parent value was sent then call its pre/post functions to let it know + // a conceptual "child" is being instantiated (e.g. that a server has + // received a connection). + if (parent != NULL) { + parent_obj = parent->object(); + env->async_hooks_pre_function()->Call(parent_obj, 0, NULL); if (try_catch.HasCaught()) - return v8::Undefined(env()->isolate()); - } - - bool has_domain = domain_v->IsObject(); - if (has_domain) { - domain = domain_v.As(); - - if (domain->Get(env()->disposed_string())->IsTrue()) - return Undefined(env()->isolate()); - - v8::Local enter = - domain->Get(env()->enter_string()).As(); - if (enter->IsFunction()) { - enter->Call(domain, 0, NULL); - if (try_catch.HasCaught()) - return Undefined(env()->isolate()); - } + FatalError("node::AsyncWrap::AsyncWrap", "parent pre hook threw"); } - v8::Local ret = cb->Call(context, argc, argv); + env->async_hooks_init_function()->Call(object, 0, NULL); - if (try_catch.HasCaught()) { - return Undefined(env()->isolate()); - } - - if (has_domain) { - v8::Local exit = - domain->Get(env()->exit_string()).As(); - if (exit->IsFunction()) { - exit->Call(domain, 0, NULL); - if (try_catch.HasCaught()) - return Undefined(env()->isolate()); - } - } + if (try_catch.HasCaught()) + FatalError("node::AsyncWrap::AsyncWrap", "init hook threw"); - if (has_async_listener()) { - v8::Local val = context.As(); - env()->async_listener_unload_function()->Call(process, 1, &val); + has_async_queue_ = true; + if (parent != NULL) { + env->async_hooks_post_function()->Call(parent_obj, 0, NULL); if (try_catch.HasCaught()) - return Undefined(env()->isolate()); + FatalError("node::AsyncWrap::AsyncWrap", "parent post hook threw"); } - - Environment::TickInfo* tick_info = env()->tick_info(); - - if (tick_info->in_tick()) { - return ret; - } - - if (tick_info->length() == 0) { - env()->isolate()->RunMicrotasks(); - } - - if (tick_info->length() == 0) { - tick_info->set_index(0); - return ret; - } - - tick_info->set_in_tick(true); - - env()->tick_callback_function()->Call(process, 0, NULL); - - tick_info->set_in_tick(false); - - if (try_catch.HasCaught()) { - tick_info->set_last_threw(true); - return Undefined(env()->isolate()); - } - - return ret; } -inline v8::Handle AsyncWrap::MakeCallback( - const v8::Handle cb, - int argc, - v8::Handle* argv) { - if (env()->using_domains()) - return MakeDomainCallback(cb, argc, argv); - - assert(env()->context() == env()->isolate()->GetCurrentContext()); - - v8::Local context = object(); - v8::Local process = env()->process_object(); - - v8::TryCatch try_catch; - try_catch.SetVerbose(true); - - if (has_async_listener()) { - v8::Local val = context.As(); - env()->async_listener_load_function()->Call(process, 1, &val); - - if (try_catch.HasCaught()) - return v8::Undefined(env()->isolate()); - } - - v8::Local ret = cb->Call(context, argc, argv); - - if (try_catch.HasCaught()) { - return Undefined(env()->isolate()); - } - - if (has_async_listener()) { - v8::Local val = context.As(); - env()->async_listener_unload_function()->Call(process, 1, &val); - - if (try_catch.HasCaught()) - return v8::Undefined(env()->isolate()); - } - - Environment::TickInfo* tick_info = env()->tick_info(); - - if (tick_info->in_tick()) { - return ret; - } - - if (tick_info->length() == 0) { - env()->isolate()->RunMicrotasks(); - } - - if (tick_info->length() == 0) { - tick_info->set_index(0); - return ret; - } - - tick_info->set_in_tick(true); - - env()->tick_callback_function()->Call(process, 0, NULL); - - tick_info->set_in_tick(false); +inline AsyncWrap::~AsyncWrap() { +} - if (try_catch.HasCaught()) { - tick_info->set_last_threw(true); - return Undefined(env()->isolate()); - } - return ret; +inline uint32_t AsyncWrap::provider_type() const { + return provider_type_; } @@ -234,10 +93,8 @@ inline v8::Handle AsyncWrap::MakeCallback( int argc, v8::Handle* argv) { v8::Local cb_v = object()->Get(symbol); - v8::Local cb = cb_v.As(); - assert(cb->IsFunction()); - - return MakeCallback(cb, argc, argv); + ASSERT(cb_v->IsFunction()); + return MakeCallback(cb_v.As(), argc, argv); } @@ -246,10 +103,8 @@ inline v8::Handle AsyncWrap::MakeCallback( int argc, v8::Handle* argv) { v8::Local cb_v = object()->Get(index); - v8::Local cb = cb_v.As(); - assert(cb->IsFunction()); - - return MakeCallback(cb, argc, argv); + ASSERT(cb_v->IsFunction()); + return MakeCallback(cb_v.As(), argc, argv); } } // namespace node diff --git a/src/async-wrap.cc b/src/async-wrap.cc new file mode 100644 index 000000000000..de1007e73d1d --- /dev/null +++ b/src/async-wrap.cc @@ -0,0 +1,188 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +#include "async-wrap.h" +#include "async-wrap-inl.h" +#include "env.h" +#include "env-inl.h" +#include "util.h" +#include "util-inl.h" + +#include "v8.h" + +using v8::Context; +using v8::Function; +using v8::FunctionCallbackInfo; +using v8::Handle; +using v8::HandleScope; +using v8::Integer; +using v8::Isolate; +using v8::Local; +using v8::Object; +using v8::TryCatch; +using v8::Value; +using v8::kExternalUint32Array; + +namespace node { + +static void SetupHooks(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args.GetIsolate()); + + CHECK(args[0]->IsObject()); + CHECK(args[1]->IsFunction()); + CHECK(args[2]->IsFunction()); + CHECK(args[3]->IsFunction()); + + // Attach Fields enum from Environment::AsyncHooks. + // Flags attached to this object are: + // - kCallInitHook (0): Tells the AsyncWrap constructor whether it should + // make a call to the init JS callback. This is disabled by default, so + // even after setting the callbacks the flag will have to be set to + // non-zero to have those callbacks called. This only affects the init + // callback. If the init callback was called, then the pre/post callbacks + // will automatically be called. + Local async_hooks_obj = args[0].As(); + Environment::AsyncHooks* async_hooks = env->async_hooks(); + async_hooks_obj->SetIndexedPropertiesToExternalArrayData( + async_hooks->fields(), + kExternalUint32Array, + async_hooks->fields_count()); + + env->set_async_hooks_init_function(args[1].As()); + env->set_async_hooks_pre_function(args[2].As()); + env->set_async_hooks_post_function(args[3].As()); +} + + +static void Initialize(Handle target, + Handle unused, + Handle context) { + Environment* env = Environment::GetCurrent(context); + Isolate* isolate = env->isolate(); + HandleScope scope(isolate); + + NODE_SET_METHOD(target, "setupHooks", SetupHooks); + + Local async_providers = Object::New(isolate); +#define V(PROVIDER) \ + async_providers->Set(FIXED_ONE_BYTE_STRING(isolate, #PROVIDER), \ + Integer::New(isolate, AsyncWrap::PROVIDER_ ## PROVIDER)); + NODE_ASYNC_PROVIDER_TYPES(V) +#undef V + target->Set(FIXED_ONE_BYTE_STRING(isolate, "Providers"), async_providers); +} + + +Handle AsyncWrap::MakeCallback(const Handle cb, + int argc, + Handle* argv) { + CHECK(env()->context() == env()->isolate()->GetCurrentContext()); + + Local context = object(); + Local process = env()->process_object(); + Local domain; + bool has_domain = false; + + if (env()->using_domains()) { + Local domain_v = context->Get(env()->domain_string()); + has_domain = domain_v->IsObject(); + if (has_domain) { + domain = domain_v.As(); + if (domain->Get(env()->disposed_string())->IsTrue()) + return Undefined(env()->isolate()); + } + } + + TryCatch try_catch; + try_catch.SetVerbose(true); + + if (has_domain) { + Local enter_v = domain->Get(env()->enter_string()); + if (enter_v->IsFunction()) { + enter_v.As()->Call(domain, 0, NULL); + if (try_catch.HasCaught()) + return Undefined(env()->isolate()); + } + } + + if (has_async_queue_) { + try_catch.SetVerbose(false); + env()->async_hooks_pre_function()->Call(context, 0, NULL); + if (try_catch.HasCaught()) + FatalError("node::AsyncWrap::MakeCallback", "pre hook threw"); + try_catch.SetVerbose(true); + } + + Local ret = cb->Call(context, argc, argv); + + if (try_catch.HasCaught()) { + return Undefined(env()->isolate()); + } + + if (has_async_queue_) { + try_catch.SetVerbose(false); + env()->async_hooks_post_function()->Call(context, 0, NULL); + if (try_catch.HasCaught()) + FatalError("node::AsyncWrap::MakeCallback", "post hook threw"); + try_catch.SetVerbose(true); + } + + if (has_domain) { + Local exit_v = domain->Get(env()->exit_string()); + if (exit_v->IsFunction()) { + exit_v.As()->Call(domain, 0, NULL); + if (try_catch.HasCaught()) + return Undefined(env()->isolate()); + } + } + + Environment::TickInfo* tick_info = env()->tick_info(); + + if (tick_info->in_tick()) { + return ret; + } + + if (tick_info->length() == 0) { + env()->isolate()->RunMicrotasks(); + } + + if (tick_info->length() == 0) { + tick_info->set_index(0); + return ret; + } + + tick_info->set_in_tick(true); + + env()->tick_callback_function()->Call(process, 0, NULL); + + tick_info->set_in_tick(false); + + if (try_catch.HasCaught()) { + tick_info->set_last_threw(true); + return Undefined(env()->isolate()); + } + + return ret; +} + +} // namespace node + +NODE_MODULE_CONTEXT_AWARE_BUILTIN(async_wrap, node::Initialize) diff --git a/src/async-wrap.h b/src/async-wrap.h index 1b1802a68ffc..403002a63f5d 100644 --- a/src/async-wrap.h +++ b/src/async-wrap.h @@ -28,49 +28,52 @@ namespace node { +#define NODE_ASYNC_PROVIDER_TYPES(V) \ + V(NONE) \ + V(CARES) \ + V(CONNECTWRAP) \ + V(CRYPTO) \ + V(FSEVENTWRAP) \ + V(FSREQWRAP) \ + V(GETADDRINFOREQWRAP) \ + V(GETNAMEINFOREQWRAP) \ + V(PIPEWRAP) \ + V(PROCESSWRAP) \ + V(QUERYWRAP) \ + V(REQWRAP) \ + V(SHUTDOWNWRAP) \ + V(SIGNALWRAP) \ + V(STATWATCHER) \ + V(TCPWRAP) \ + V(TIMERWRAP) \ + V(TLSWRAP) \ + V(TTYWRAP) \ + V(UDPWRAP) \ + V(WRITEWRAP) \ + V(ZLIB) + class AsyncWrap : public BaseObject { public: - enum AsyncFlags { - NO_OPTIONS = 0, - HAS_ASYNC_LISTENER = 1 - }; - enum ProviderType { - PROVIDER_NONE = 1 << 0, - PROVIDER_CARES = 1 << 1, - PROVIDER_CONNECTWRAP = 1 << 2, - PROVIDER_CRYPTO = 1 << 3, - PROVIDER_FSEVENTWRAP = 1 << 4, - PROVIDER_GETADDRINFOREQWRAP = 1 << 5, - PROVIDER_PIPEWRAP = 1 << 6, - PROVIDER_PROCESSWRAP = 1 << 7, - PROVIDER_REQWRAP = 1 << 8, - PROVIDER_SHUTDOWNWRAP = 1 << 9, - PROVIDER_SIGNALWRAP = 1 << 10, - PROVIDER_STATWATCHER = 1 << 11, - PROVIDER_TCPWRAP = 1 << 12, - PROVIDER_TIMERWRAP = 1 << 13, - PROVIDER_TLSWRAP = 1 << 14, - PROVIDER_TTYWRAP = 1 << 15, - PROVIDER_UDPWRAP = 1 << 16, - PROVIDER_ZLIB = 1 << 17, - PROVIDER_GETNAMEINFOREQWRAP = 1 << 18 +#define V(PROVIDER) \ + PROVIDER_ ## PROVIDER, + NODE_ASYNC_PROVIDER_TYPES(V) +#undef V }; inline AsyncWrap(Environment* env, v8::Handle object, - ProviderType provider); + ProviderType provider, + AsyncWrap* parent = NULL); inline ~AsyncWrap(); - inline bool has_async_listener(); - inline uint32_t provider_type() const; // Only call these within a valid HandleScope. - inline v8::Handle MakeCallback(const v8::Handle cb, - int argc, - v8::Handle* argv); + v8::Handle MakeCallback(const v8::Handle cb, + int argc, + v8::Handle* argv); inline v8::Handle MakeCallback(const v8::Handle symbol, int argc, v8::Handle* argv); @@ -81,15 +84,11 @@ class AsyncWrap : public BaseObject { private: inline AsyncWrap(); - // TODO(trevnorris): BURN IN FIRE! Remove this as soon as a suitable - // replacement is committed. - inline v8::Handle MakeDomainCallback( - const v8::Handle cb, - int argc, - v8::Handle* argv); - - uint32_t async_flags_; - uint32_t provider_type_; + // When the async hooks init JS function is called from the constructor it is + // expected the context object will receive a _asyncQueue object property + // that will be used to call pre/post in MakeCallback. + bool has_async_queue_; + ProviderType provider_type_; }; } // namespace node diff --git a/src/base-object-inl.h b/src/base-object-inl.h index 4d726df7ca79..8cd9e2fd0738 100644 --- a/src/base-object-inl.h +++ b/src/base-object-inl.h @@ -72,7 +72,7 @@ inline void BaseObject::MakeWeak(Type* ptr) { v8::HandleScope scope(env_->isolate()); v8::Local handle = object(); assert(handle->InternalFieldCount() > 0); - Wrap(handle, ptr); + Wrap(handle, ptr); handle_.MarkIndependent(); handle_.SetWeak(ptr, WeakCallback); } diff --git a/src/cares_wrap.cc b/src/cares_wrap.cc index 66b4806e7ef6..39c880015636 100644 --- a/src/cares_wrap.cc +++ b/src/cares_wrap.cc @@ -55,6 +55,7 @@ using v8::Context; using v8::EscapableHandleScope; using v8::Function; using v8::FunctionCallbackInfo; +using v8::FunctionTemplate; using v8::Handle; using v8::HandleScope; using v8::Integer; @@ -64,8 +65,39 @@ using v8::Object; using v8::String; using v8::Value; -typedef class ReqWrap GetAddrInfoReqWrap; -typedef class ReqWrap GetNameInfoReqWrap; + +class GetAddrInfoReqWrap : public ReqWrap { + public: + GetAddrInfoReqWrap(Environment* env, Local req_wrap_obj); +}; + +GetAddrInfoReqWrap::GetAddrInfoReqWrap(Environment* env, + Local req_wrap_obj) + : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_GETADDRINFOREQWRAP) { + Wrap(req_wrap_obj, this); +} + + +static void NewGetAddrInfoReqWrap(const FunctionCallbackInfo& args) { + CHECK(args.IsConstructCall()); +} + + +class GetNameInfoReqWrap : public ReqWrap { + public: + GetNameInfoReqWrap(Environment* env, Local req_wrap_obj); +}; + +GetNameInfoReqWrap::GetNameInfoReqWrap(Environment* env, + Local req_wrap_obj) + : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_GETNAMEINFOREQWRAP) { + Wrap(req_wrap_obj, this); +} + + +static void NewGetNameInfoReqWrap(const FunctionCallbackInfo& args) { + CHECK(args.IsConstructCall()); +} static int cmp_ares_tasks(const ares_task_t* a, const ares_task_t* b) { @@ -229,7 +261,7 @@ static Local HostentToNames(Environment* env, struct hostent* host) { class QueryWrap : public AsyncWrap { public: QueryWrap(Environment* env, Local req_wrap_obj) - : AsyncWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_CARES) { + : AsyncWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_QUERYWRAP) { if (env->in_domain()) req_wrap_obj->Set(env->domain_string(), env->domain_array()->Get(0)); } @@ -1037,10 +1069,7 @@ static void GetAddrInfo(const FunctionCallbackInfo& args) { abort(); } - GetAddrInfoReqWrap* req_wrap = - new GetAddrInfoReqWrap(env, - req_wrap_obj, - AsyncWrap::PROVIDER_GETADDRINFOREQWRAP); + GetAddrInfoReqWrap* req_wrap = new GetAddrInfoReqWrap(env, req_wrap_obj); struct addrinfo hints; memset(&hints, 0, sizeof(struct addrinfo)); @@ -1077,10 +1106,7 @@ static void GetNameInfo(const FunctionCallbackInfo& args) { CHECK(uv_ip4_addr(*ip, port, reinterpret_cast(&addr)) == 0 || uv_ip6_addr(*ip, port, reinterpret_cast(&addr)) == 0); - GetNameInfoReqWrap* req_wrap = - new GetNameInfoReqWrap(env, - req_wrap_obj, - AsyncWrap::PROVIDER_GETNAMEINFOREQWRAP); + GetNameInfoReqWrap* req_wrap = new GetNameInfoReqWrap(env, req_wrap_obj); int err = uv_getnameinfo(env->event_loop(), &req_wrap->req_, @@ -1273,6 +1299,22 @@ static void Initialize(Handle target, Integer::New(env->isolate(), AI_ADDRCONFIG)); target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "AI_V4MAPPED"), Integer::New(env->isolate(), AI_V4MAPPED)); + + Local aiw = + FunctionTemplate::New(env->isolate(), NewGetAddrInfoReqWrap); + aiw->InstanceTemplate()->SetInternalFieldCount(1); + aiw->SetClassName( + FIXED_ONE_BYTE_STRING(env->isolate(), "GetAddrInfoReqWrap")); + target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "GetAddrInfoReqWrap"), + aiw->GetFunction()); + + Local niw = + FunctionTemplate::New(env->isolate(), NewGetNameInfoReqWrap); + niw->InstanceTemplate()->SetInternalFieldCount(1); + niw->SetClassName( + FIXED_ONE_BYTE_STRING(env->isolate(), "GetNameInfoReqWrap")); + target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "GetNameInfoReqWrap"), + niw->GetFunction()); } } // namespace cares_wrap diff --git a/src/env-inl.h b/src/env-inl.h index e6a3d1c5ecf0..a2245130664b 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -111,25 +111,20 @@ inline v8::Isolate* Environment::IsolateData::isolate() const { return isolate_; } -inline Environment::AsyncListener::AsyncListener() { - for (int i = 0; i < kFieldsCount; ++i) - fields_[i] = 0; +inline Environment::AsyncHooks::AsyncHooks() { + for (int i = 0; i < kFieldsCount; i++) fields_[i] = 0; } -inline uint32_t* Environment::AsyncListener::fields() { +inline uint32_t* Environment::AsyncHooks::fields() { return fields_; } -inline int Environment::AsyncListener::fields_count() const { +inline int Environment::AsyncHooks::fields_count() const { return kFieldsCount; } -inline bool Environment::AsyncListener::has_listener() const { - return fields_[kHasListener] > 0; -} - -inline uint32_t Environment::AsyncListener::watched_providers() const { - return fields_[kWatchedProviders]; +inline bool Environment::AsyncHooks::call_init_hook() { + return fields_[kCallInitHook] != 0; } inline Environment::DomainFlag::DomainFlag() { @@ -264,14 +259,9 @@ inline v8::Isolate* Environment::isolate() const { return isolate_; } -inline bool Environment::has_async_listener() const { - // The const_cast is okay, it doesn't violate conceptual const-ness. - return const_cast(this)->async_listener()->has_listener(); -} - -inline uint32_t Environment::watched_providers() const { +inline bool Environment::call_async_init_hook() const { // The const_cast is okay, it doesn't violate conceptual const-ness. - return const_cast(this)->async_listener()->watched_providers(); + return const_cast(this)->async_hooks()->call_init_hook(); } inline bool Environment::in_domain() const { @@ -325,8 +315,8 @@ inline uv_loop_t* Environment::event_loop() const { return isolate_data()->event_loop(); } -inline Environment::AsyncListener* Environment::async_listener() { - return &async_listener_count_; +inline Environment::AsyncHooks* Environment::async_hooks() { + return &async_hooks_; } inline Environment::DomainFlag* Environment::domain_flag() { diff --git a/src/env.h b/src/env.h index 655e804cb9e5..e028a23f0483 100644 --- a/src/env.h +++ b/src/env.h @@ -64,8 +64,8 @@ namespace node { V(address_string, "address") \ V(args_string, "args") \ V(argv_string, "argv") \ - V(async_queue_string, "_asyncQueue") \ V(async, "async") \ + V(async_queue_string, "_asyncQueue") \ V(atime_string, "atime") \ V(birthtime_string, "birthtime") \ V(blksize_string, "blksize") \ @@ -250,9 +250,9 @@ namespace node { V(zero_return_string, "ZERO_RETURN") \ #define ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V) \ - V(async_listener_run_function, v8::Function) \ - V(async_listener_load_function, v8::Function) \ - V(async_listener_unload_function, v8::Function) \ + V(async_hooks_init_function, v8::Function) \ + V(async_hooks_pre_function, v8::Function) \ + V(async_hooks_post_function, v8::Function) \ V(binding_cache_object, v8::Object) \ V(buffer_constructor_function, v8::Function) \ V(context, v8::Context) \ @@ -286,26 +286,25 @@ RB_HEAD(ares_task_list, ares_task_t); class Environment { public: - class AsyncListener { + class AsyncHooks { public: inline uint32_t* fields(); inline int fields_count() const; - inline bool has_listener() const; - inline uint32_t watched_providers() const; + inline bool call_init_hook(); private: friend class Environment; // So we can call the constructor. - inline AsyncListener(); + inline AsyncHooks(); enum Fields { - kHasListener, - kWatchedProviders, + // Set this to not zero if the init hook should be called. + kCallInitHook, kFieldsCount }; uint32_t fields_[kFieldsCount]; - DISALLOW_COPY_AND_ASSIGN(AsyncListener); + DISALLOW_COPY_AND_ASSIGN(AsyncHooks); }; class DomainFlag { @@ -395,7 +394,7 @@ class Environment { inline v8::Isolate* isolate() const; inline uv_loop_t* event_loop() const; - inline bool has_async_listener() const; + inline bool call_async_init_hook() const; inline bool in_domain() const; inline uint32_t watched_providers() const; @@ -415,7 +414,7 @@ class Environment { void *arg); inline void FinishHandleCleanup(uv_handle_t* handle); - inline AsyncListener* async_listener(); + inline AsyncHooks* async_hooks(); inline DomainFlag* domain_flag(); inline TickInfo* tick_info(); @@ -492,7 +491,7 @@ class Environment { uv_idle_t immediate_idle_handle_; uv_prepare_t idle_prepare_handle_; uv_check_t idle_check_handle_; - AsyncListener async_listener_count_; + AsyncHooks async_hooks_; DomainFlag domain_flag_; TickInfo tick_info_; uv_timer_t cares_timer_handle_; diff --git a/src/handle_wrap.cc b/src/handle_wrap.cc index 83015f1dfd8f..a355e5bbba54 100644 --- a/src/handle_wrap.cc +++ b/src/handle_wrap.cc @@ -90,13 +90,14 @@ void HandleWrap::Close(const FunctionCallbackInfo& args) { HandleWrap::HandleWrap(Environment* env, Handle object, uv_handle_t* handle, - AsyncWrap::ProviderType provider) - : AsyncWrap(env, object, provider), + AsyncWrap::ProviderType provider, + AsyncWrap* parent) + : AsyncWrap(env, object, provider, parent), flags_(0), handle__(handle) { handle__->data = this; HandleScope scope(env->isolate()); - Wrap(object, this); + Wrap(object, this); QUEUE_INSERT_TAIL(env->handle_wrap_queue(), &handle_wrap_queue_); } diff --git a/src/handle_wrap.h b/src/handle_wrap.h index 4f6f6e032369..95551a756355 100644 --- a/src/handle_wrap.h +++ b/src/handle_wrap.h @@ -63,7 +63,8 @@ class HandleWrap : public AsyncWrap { HandleWrap(Environment* env, v8::Handle object, uv_handle_t* handle, - AsyncWrap::ProviderType provider); + AsyncWrap::ProviderType provider, + AsyncWrap* parent = NULL); virtual ~HandleWrap(); private: diff --git a/src/node.cc b/src/node.cc index 5a9d0fc12caa..d15b47577f4a 100644 --- a/src/node.cc +++ b/src/node.cc @@ -909,32 +909,6 @@ Local WinapiErrnoException(Isolate* isolate, #endif -void SetupAsyncListener(const FunctionCallbackInfo& args) { - HandleScope handle_scope(args.GetIsolate()); - Environment* env = Environment::GetCurrent(args.GetIsolate()); - - assert(args[0]->IsObject()); - assert(args[1]->IsFunction()); - assert(args[2]->IsFunction()); - assert(args[3]->IsFunction()); - - env->set_async_listener_run_function(args[1].As()); - env->set_async_listener_load_function(args[2].As()); - env->set_async_listener_unload_function(args[3].As()); - - Local async_listener_flag_obj = args[0].As(); - Environment::AsyncListener* async_listener = env->async_listener(); - async_listener_flag_obj->SetIndexedPropertiesToExternalArrayData( - async_listener->fields(), - kExternalUint32Array, - async_listener->fields_count()); - - // Do a little housekeeping. - env->process_object()->Delete( - FIXED_ONE_BYTE_STRING(args.GetIsolate(), "_setupAsyncListener")); -} - - void SetupDomainUse(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args.GetIsolate()); @@ -1004,152 +978,80 @@ void SetupNextTick(const FunctionCallbackInfo& args) { } -Handle MakeDomainCallback(Environment* env, - Handle recv, - const Handle callback, - int argc, - Handle argv[]) { +Handle MakeCallback(Environment* env, + Handle recv, + const Handle callback, + int argc, + Handle argv[]) { // If you hit this assertion, you forgot to enter the v8::Context first. - assert(env->context() == env->isolate()->GetCurrentContext()); + CHECK(env->context() == env->isolate()->GetCurrentContext()); Local process = env->process_object(); Local object, domain; - Local domain_v; - - TryCatch try_catch; - try_catch.SetVerbose(true); - bool has_async_queue = false; + bool has_domain = false; if (recv->IsObject()) { object = recv.As(); - // TODO(trevnorris): This is sucky for performance. Fix it. - has_async_queue = object->Has(env->async_queue_string()); - if (has_async_queue) { - env->async_listener_load_function()->Call(process, 1, &recv); - - if (try_catch.HasCaught()) - return Undefined(env->isolate()); - } + Local async_queue_v = object->Get(env->async_queue_string()); + if (async_queue_v->IsObject()) + has_async_queue = true; } - bool has_domain = false; - - if (!object.IsEmpty()) { - domain_v = object->Get(env->domain_string()); + if (env->using_domains()) { + CHECK(recv->IsObject()); + Local domain_v = object->Get(env->domain_string()); has_domain = domain_v->IsObject(); if (has_domain) { domain = domain_v.As(); - - if (domain->Get(env->disposed_string())->IsTrue()) { - // domain has been disposed of. + if (domain->Get(env->disposed_string())->IsTrue()) return Undefined(env->isolate()); - } - - Local enter = domain->Get(env->enter_string()).As(); - if (enter->IsFunction()) { - enter->Call(domain, 0, NULL); - if (try_catch.HasCaught()) - return Undefined(env->isolate()); - } } } - Local ret = callback->Call(recv, argc, argv); - - if (try_catch.HasCaught()) { - return Undefined(env->isolate()); - } + TryCatch try_catch; + try_catch.SetVerbose(true); if (has_domain) { - Local exit = domain->Get(env->exit_string()).As(); - if (exit->IsFunction()) { - exit->Call(domain, 0, NULL); + Local enter_v = domain->Get(env->enter_string()); + if (enter_v->IsFunction()) { + enter_v.As()->Call(domain, 0, NULL); if (try_catch.HasCaught()) return Undefined(env->isolate()); } } if (has_async_queue) { - env->async_listener_unload_function()->Call(process, 1, &recv); - + try_catch.SetVerbose(false); + env->async_hooks_pre_function()->Call(object, 0, NULL); if (try_catch.HasCaught()) - return Undefined(env->isolate()); - } - - Environment::TickInfo* tick_info = env->tick_info(); - - if (tick_info->last_threw() == 1) { - tick_info->set_last_threw(0); - return ret; - } - - if (tick_info->in_tick()) { - return ret; - } - - if (tick_info->length() == 0) { - env->isolate()->RunMicrotasks(); + FatalError("node:;MakeCallback", "pre hook threw"); + try_catch.SetVerbose(true); } - if (tick_info->length() == 0) { - tick_info->set_index(0); - return ret; - } - - tick_info->set_in_tick(true); - - env->tick_callback_function()->Call(process, 0, NULL); - - tick_info->set_in_tick(false); - - if (try_catch.HasCaught()) { - tick_info->set_last_threw(true); - return Undefined(env->isolate()); - } - - return ret; -} - - -Handle MakeCallback(Environment* env, - Handle recv, - const Handle callback, - int argc, - Handle argv[]) { - if (env->using_domains()) - return MakeDomainCallback(env, recv, callback, argc, argv); - - // If you hit this assertion, you forgot to enter the v8::Context first. - assert(env->context() == env->isolate()->GetCurrentContext()); - - Local process = env->process_object(); - - TryCatch try_catch; - try_catch.SetVerbose(true); + Local ret = callback->Call(recv, argc, argv); - // TODO(trevnorris): This is sucky for performance. Fix it. - bool has_async_queue = - recv->IsObject() && recv.As()->Has(env->async_queue_string()); if (has_async_queue) { - env->async_listener_load_function()->Call(process, 1, &recv); + try_catch.SetVerbose(false); + env->async_hooks_post_function()->Call(object, 0, NULL); if (try_catch.HasCaught()) - return Undefined(env->isolate()); + FatalError("node::MakeCallback", "post hook threw"); + try_catch.SetVerbose(true); } - Local ret = callback->Call(recv, argc, argv); + if (has_domain) { + Local exit_v = domain->Get(env->exit_string()); + if (exit_v->IsFunction()) { + exit_v.As()->Call(domain, 0, NULL); + if (try_catch.HasCaught()) + return Undefined(env->isolate()); + } + } if (try_catch.HasCaught()) { return Undefined(env->isolate()); } - if (has_async_queue) { - env->async_listener_unload_function()->Call(process, 1, &recv); - - if (try_catch.HasCaught()) - return Undefined(env->isolate()); - } - Environment::TickInfo* tick_info = env->tick_info(); if (tick_info->in_tick()) { @@ -1187,10 +1089,9 @@ Handle MakeCallback(Environment* env, uint32_t index, int argc, Handle argv[]) { - Local callback = recv->Get(index).As(); - assert(callback->IsFunction()); - - return MakeCallback(env, recv.As(), callback, argc, argv); + Local cb_v = recv->Get(index); + CHECK(cb_v->IsFunction()); + return MakeCallback(env, recv.As(), cb_v.As(), argc, argv); } @@ -1199,9 +1100,9 @@ Handle MakeCallback(Environment* env, Handle symbol, int argc, Handle argv[]) { - Local callback = recv->Get(symbol).As(); - assert(callback->IsFunction()); - return MakeCallback(env, recv.As(), callback, argc, argv); + Local cb_v = recv->Get(symbol); + CHECK(cb_v->IsFunction()); + return MakeCallback(env, recv.As(), cb_v.As(), argc, argv); } @@ -1258,20 +1159,6 @@ Handle MakeCallback(Isolate* isolate, } -Handle MakeDomainCallback(Handle recv, - Handle callback, - int argc, - Handle argv[]) { - Local context = recv->CreationContext(); - Environment* env = Environment::GetCurrent(context); - Context::Scope context_scope(context); - EscapableHandleScope handle_scope(env->isolate()); - return handle_scope.Escape(Local::New( - env->isolate(), - MakeDomainCallback(env, recv, callback, argc, argv))); -} - - enum encoding ParseEncoding(Isolate* isolate, Handle encoding_v, enum encoding _default) { @@ -2880,7 +2767,6 @@ void SetupProcessObject(Environment* env, NODE_SET_METHOD(process, "binding", Binding); NODE_SET_METHOD(process, "_linkedBinding", LinkedBinding); - NODE_SET_METHOD(process, "_setupAsyncListener", SetupAsyncListener); NODE_SET_METHOD(process, "_setupNextTick", SetupNextTick); NODE_SET_METHOD(process, "_setupDomainUse", SetupDomainUse); diff --git a/src/node.js b/src/node.js index 59cca4e748cd..50460383ff71 100644 --- a/src/node.js +++ b/src/node.js @@ -39,9 +39,6 @@ process.EventEmitter = EventEmitter; // process.EventEmitter is deprecated - // Setup the tracing module - NativeModule.require('tracing')._nodeInitialization(process); - // do this good and early, since it handles errors. startup.processFatal(); @@ -229,14 +226,8 @@ }; startup.processFatal = function() { - var tracing = NativeModule.require('tracing'); - var _errorHandler = tracing._errorHandler; - // Cleanup - delete tracing._errorHandler; - process._fatalException = function(er) { - // First run through error handlers from asyncListener. - var caught = _errorHandler(er); + var caught; if (process.domain && process.domain._errorHandler) caught = process.domain._errorHandler(er) || caught; @@ -258,11 +249,7 @@ // if we handled an error, then make sure any ticks get processed } else { - var t = setImmediate(process._tickCallback); - // Complete hack to make sure any errors thrown from async - // listeners don't cause an infinite loop. - if (t._asyncQueue) - t._asyncQueue = []; + NativeModule.require('timers').setImmediate(process._tickCallback); } return caught; @@ -296,12 +283,7 @@ }; startup.processNextTick = function() { - var tracing = NativeModule.require('tracing'); var nextTickQueue = []; - var asyncFlags = tracing._asyncFlags; - var _runAsyncQueue = tracing._runAsyncQueue; - var _loadAsyncQueue = tracing._loadAsyncQueue; - var _unloadAsyncQueue = tracing._unloadAsyncQueue; var microtasksScheduled = false; // Used to run V8's micro task queue. @@ -315,10 +297,6 @@ var kIndex = 0; var kLength = 1; - // For asyncFlags. - // *Must* match Environment::AsyncListeners::Fields in src/env.h - var kCount = 0; - process.nextTick = nextTick; // Needs to be accessible from beyond this scope. process._tickCallback = _tickCallback; @@ -365,7 +343,7 @@ // Run callbacks that have no domain. // Using domains will cause this to be overridden. function _tickCallback() { - var callback, hasQueue, threw, tock; + var callback, threw, tock; scheduleMicrotasks(); @@ -373,9 +351,6 @@ tock = nextTickQueue[tickInfo[kIndex]++]; callback = tock.callback; threw = true; - hasQueue = !!tock._asyncQueue; - if (hasQueue) - _loadAsyncQueue(tock); try { callback(); threw = false; @@ -383,8 +358,6 @@ if (threw) tickDone(); } - if (hasQueue) - _unloadAsyncQueue(tock); if (1e4 < tickInfo[kIndex]) tickDone(); } @@ -393,7 +366,7 @@ } function _tickDomainCallback() { - var callback, domain, hasQueue, threw, tock; + var callback, domain, threw, tock; scheduleMicrotasks(); @@ -401,9 +374,6 @@ tock = nextTickQueue[tickInfo[kIndex]++]; callback = tock.callback; domain = tock.domain; - hasQueue = !!tock._asyncQueue; - if (hasQueue) - _loadAsyncQueue(tock); if (domain) domain.enter(); threw = true; @@ -414,8 +384,6 @@ if (threw) tickDone(); } - if (hasQueue) - _unloadAsyncQueue(tock); if (1e4 < tickInfo[kIndex]) tickDone(); if (domain) @@ -432,13 +400,9 @@ var obj = { callback: callback, - domain: process.domain || null, - _asyncQueue: undefined + domain: process.domain || null }; - if (asyncFlags[kCount] > 0) - _runAsyncQueue(obj); - nextTickQueue.push(obj); tickInfo[kLength]++; } diff --git a/src/node_contextify.cc b/src/node_contextify.cc index 3f190a407b6b..2e8fd2cade62 100644 --- a/src/node_contextify.cc +++ b/src/node_contextify.cc @@ -205,7 +205,7 @@ class ContextifyContext { if (wrapper.IsEmpty()) return scope.Escape(Local::New(env->isolate(), Handle())); - Wrap(wrapper, this); + Wrap(wrapper, this); return scope.Escape(wrapper); } diff --git a/src/node_file.cc b/src/node_file.cc index de43b92e6e06..6736864bc57c 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -71,11 +71,15 @@ class FSReqWrap: public ReqWrap { void* operator new(size_t size) { return new char[size]; } void* operator new(size_t size, char* storage) { return storage; } - FSReqWrap(Environment* env, const char* syscall, char* data = NULL) - : ReqWrap(env, Object::New(env->isolate())), + FSReqWrap(Environment* env, + Local req, + const char* syscall, + char* data = NULL) + : ReqWrap(env, req, AsyncWrap::PROVIDER_FSREQWRAP), syscall_(syscall), data_(data), dest_len_(0) { + Wrap(object(), this); } void ReleaseEarly() { @@ -98,6 +102,11 @@ class FSReqWrap: public ReqWrap { }; +static void NewFSReqWrap(const FunctionCallbackInfo& args) { + CHECK(args.IsConstructCall()); +} + + #define ASSERT_OFFSET(a) \ if (!(a)->IsUndefined() && !(a)->IsNull() && !IsInt64((a)->NumberValue())) { \ return env->ThrowTypeError("Not an integer"); \ @@ -256,35 +265,35 @@ struct fs_req_wrap { }; -#define ASYNC_DEST_CALL(func, callback, dest_path, ...) \ +#define ASYNC_DEST_CALL(func, req, dest_path, ...) \ Environment* env = Environment::GetCurrent(args.GetIsolate()); \ FSReqWrap* req_wrap; \ char* dest_str = (dest_path); \ int dest_len = dest_str == NULL ? 0 : strlen(dest_str); \ char* storage = new char[sizeof(*req_wrap) + dest_len]; \ - req_wrap = new(storage) FSReqWrap(env, #func); \ + CHECK(req->IsObject()); \ + req_wrap = new(storage) FSReqWrap(env, req.As(), #func); \ req_wrap->dest_len(dest_len); \ if (dest_str != NULL) { \ memcpy(const_cast(req_wrap->dest()), \ dest_str, \ dest_len + 1); \ } \ - int err = uv_fs_ ## func(env->event_loop() , \ + int err = uv_fs_ ## func(env->event_loop(), \ &req_wrap->req_, \ __VA_ARGS__, \ After); \ - req_wrap->object()->Set(env->oncomplete_string(), callback); \ req_wrap->Dispatched(); \ if (err < 0) { \ - uv_fs_t* req = &req_wrap->req_; \ - req->result = err; \ - req->path = NULL; \ - After(req); \ + uv_fs_t* uv_req = &req_wrap->req_; \ + uv_req->result = err; \ + uv_req->path = NULL; \ + After(uv_req); \ } \ args.GetReturnValue().Set(req_wrap->persistent()); -#define ASYNC_CALL(func, callback, ...) \ - ASYNC_DEST_CALL(func, callback, NULL, __VA_ARGS__) \ +#define ASYNC_CALL(func, req, ...) \ + ASYNC_DEST_CALL(func, req, NULL, __VA_ARGS__) \ #define SYNC_DEST_CALL(func, path, dest, ...) \ fs_req_wrap req_wrap; \ @@ -321,7 +330,7 @@ static void Close(const FunctionCallbackInfo& args) { int fd = args[0]->Int32Value(); - if (args[1]->IsFunction()) { + if (args[1]->IsObject()) { ASYNC_CALL(close, args[1], fd) } else { SYNC_CALL(close, 0, fd) @@ -437,7 +446,7 @@ static void Stat(const FunctionCallbackInfo& args) { node::Utf8Value path(args[0]); - if (args[1]->IsFunction()) { + if (args[1]->IsObject()) { ASYNC_CALL(stat, args[1], *path) } else { SYNC_CALL(stat, *path, *path) @@ -457,7 +466,7 @@ static void LStat(const FunctionCallbackInfo& args) { node::Utf8Value path(args[0]); - if (args[1]->IsFunction()) { + if (args[1]->IsObject()) { ASYNC_CALL(lstat, args[1], *path) } else { SYNC_CALL(lstat, *path, *path) @@ -476,7 +485,7 @@ static void FStat(const FunctionCallbackInfo& args) { int fd = args[0]->Int32Value(); - if (args[1]->IsFunction()) { + if (args[1]->IsObject()) { ASYNC_CALL(fstat, args[1], fd) } else { SYNC_CALL(fstat, 0, fd) @@ -514,7 +523,7 @@ static void Symlink(const FunctionCallbackInfo& args) { } } - if (args[3]->IsFunction()) { + if (args[3]->IsObject()) { ASYNC_DEST_CALL(symlink, args[3], *path, *dest, *path, flags) } else { SYNC_DEST_CALL(symlink, *dest, *path, *dest, *path, flags) @@ -538,7 +547,7 @@ static void Link(const FunctionCallbackInfo& args) { node::Utf8Value orig_path(args[0]); node::Utf8Value new_path(args[1]); - if (args[2]->IsFunction()) { + if (args[2]->IsObject()) { ASYNC_DEST_CALL(link, args[2], *new_path, *orig_path, *new_path) } else { SYNC_DEST_CALL(link, *orig_path, *new_path, *orig_path, *new_path) @@ -556,7 +565,7 @@ static void ReadLink(const FunctionCallbackInfo& args) { node::Utf8Value path(args[0]); - if (args[1]->IsFunction()) { + if (args[1]->IsObject()) { ASYNC_CALL(readlink, args[1], *path) } else { SYNC_CALL(readlink, *path, *path) @@ -583,7 +592,7 @@ static void Rename(const FunctionCallbackInfo& args) { node::Utf8Value old_path(args[0]); node::Utf8Value new_path(args[1]); - if (args[2]->IsFunction()) { + if (args[2]->IsObject()) { ASYNC_DEST_CALL(rename, args[2], *new_path, *old_path, *new_path) } else { SYNC_DEST_CALL(rename, *old_path, *new_path, *old_path, *new_path) @@ -603,7 +612,7 @@ static void FTruncate(const FunctionCallbackInfo& args) { ASSERT_TRUNCATE_LENGTH(args[1]); int64_t len = GET_TRUNCATE_LENGTH(args[1]); - if (args[2]->IsFunction()) { + if (args[2]->IsObject()) { ASYNC_CALL(ftruncate, args[2], fd, len) } else { SYNC_CALL(ftruncate, 0, fd, len) @@ -620,7 +629,7 @@ static void Fdatasync(const FunctionCallbackInfo& args) { int fd = args[0]->Int32Value(); - if (args[1]->IsFunction()) { + if (args[1]->IsObject()) { ASYNC_CALL(fdatasync, args[1], fd) } else { SYNC_CALL(fdatasync, 0, fd) @@ -637,7 +646,7 @@ static void Fsync(const FunctionCallbackInfo& args) { int fd = args[0]->Int32Value(); - if (args[1]->IsFunction()) { + if (args[1]->IsObject()) { ASYNC_CALL(fsync, args[1], fd) } else { SYNC_CALL(fsync, 0, fd) @@ -655,7 +664,7 @@ static void Unlink(const FunctionCallbackInfo& args) { node::Utf8Value path(args[0]); - if (args[1]->IsFunction()) { + if (args[1]->IsObject()) { ASYNC_CALL(unlink, args[1], *path) } else { SYNC_CALL(unlink, *path, *path) @@ -673,7 +682,7 @@ static void RMDir(const FunctionCallbackInfo& args) { node::Utf8Value path(args[0]); - if (args[1]->IsFunction()) { + if (args[1]->IsObject()) { ASYNC_CALL(rmdir, args[1], *path) } else { SYNC_CALL(rmdir, *path, *path) @@ -691,7 +700,7 @@ static void MKDir(const FunctionCallbackInfo& args) { node::Utf8Value path(args[0]); int mode = static_cast(args[1]->Int32Value()); - if (args[2]->IsFunction()) { + if (args[2]->IsObject()) { ASYNC_CALL(mkdir, args[2], *path, mode) } else { SYNC_CALL(mkdir, *path, *path, mode) @@ -709,7 +718,7 @@ static void ReadDir(const FunctionCallbackInfo& args) { node::Utf8Value path(args[0]); - if (args[1]->IsFunction()) { + if (args[1]->IsObject()) { ASYNC_CALL(scandir, args[1], *path, 0 /*flags*/) } else { SYNC_CALL(scandir, *path, *path, 0 /*flags*/) @@ -758,7 +767,7 @@ static void Open(const FunctionCallbackInfo& args) { int flags = args[1]->Int32Value(); int mode = static_cast(args[2]->Int32Value()); - if (args[3]->IsFunction()) { + if (args[3]->IsObject()) { ASYNC_CALL(open, args[3], *path, flags, mode) } else { SYNC_CALL(open, *path, *path, flags, mode) @@ -790,7 +799,7 @@ static void WriteBuffer(const FunctionCallbackInfo& args) { size_t off = args[2]->Uint32Value(); size_t len = args[3]->Uint32Value(); int64_t pos = GET_OFFSET(args[4]); - Local cb = args[5]; + Local req = args[5]; if (off > buffer_length) return env->ThrowRangeError("offset out of bounds"); @@ -805,8 +814,8 @@ static void WriteBuffer(const FunctionCallbackInfo& args) { uv_buf_t uvbuf = uv_buf_init(const_cast(buf), len); - if (cb->IsFunction()) { - ASYNC_CALL(write, cb, fd, &uvbuf, 1, pos) + if (req->IsObject()) { + ASYNC_CALL(write, req, fd, &uvbuf, 1, pos) return; } @@ -830,7 +839,7 @@ static void WriteString(const FunctionCallbackInfo& args) { if (!args[0]->IsInt32()) return env->ThrowTypeError("First argument must be file descriptor"); - Local cb; + Local req; Local string = args[1]; int fd = args[0]->Int32Value(); char* buf = NULL; @@ -852,18 +861,19 @@ static void WriteString(const FunctionCallbackInfo& args) { must_free = true; } pos = GET_OFFSET(args[2]); - cb = args[4]; + req = args[4]; uv_buf_t uvbuf = uv_buf_init(const_cast(buf), len); - if (!cb->IsFunction()) { + if (!req->IsObject()) { SYNC_CALL(write, NULL, fd, &uvbuf, 1, pos) if (must_free) delete[] buf; return args.GetReturnValue().Set(SYNC_RESULT); } - FSReqWrap* req_wrap = new FSReqWrap(env, "write", must_free ? buf : NULL); + FSReqWrap* req_wrap = + new FSReqWrap(env, req.As(), "write", must_free ? buf : NULL); int err = uv_fs_write(env->event_loop(), &req_wrap->req_, fd, @@ -871,7 +881,6 @@ static void WriteString(const FunctionCallbackInfo& args) { 1, pos, After); - req_wrap->object()->Set(env->oncomplete_string(), cb); req_wrap->Dispatched(); if (err < 0) { uv_fs_t* req = &req_wrap->req_; @@ -906,7 +915,7 @@ static void Read(const FunctionCallbackInfo& args) { int fd = args[0]->Int32Value(); - Local cb; + Local req; size_t len; int64_t pos; @@ -936,10 +945,10 @@ static void Read(const FunctionCallbackInfo& args) { uv_buf_t uvbuf = uv_buf_init(const_cast(buf), len); - cb = args[5]; + req = args[5]; - if (cb->IsFunction()) { - ASYNC_CALL(read, cb, fd, &uvbuf, 1, pos); + if (req->IsObject()) { + ASYNC_CALL(read, req, fd, &uvbuf, 1, pos); } else { SYNC_CALL(read, 0, fd, &uvbuf, 1, pos) args.GetReturnValue().Set(SYNC_RESULT); @@ -960,7 +969,7 @@ static void Chmod(const FunctionCallbackInfo& args) { node::Utf8Value path(args[0]); int mode = static_cast(args[1]->Int32Value()); - if (args[2]->IsFunction()) { + if (args[2]->IsObject()) { ASYNC_CALL(chmod, args[2], *path, mode); } else { SYNC_CALL(chmod, *path, *path, mode); @@ -981,7 +990,7 @@ static void FChmod(const FunctionCallbackInfo& args) { int fd = args[0]->Int32Value(); int mode = static_cast(args[1]->Int32Value()); - if (args[2]->IsFunction()) { + if (args[2]->IsObject()) { ASYNC_CALL(fchmod, args[2], fd, mode); } else { SYNC_CALL(fchmod, 0, fd, mode); @@ -1014,7 +1023,7 @@ static void Chown(const FunctionCallbackInfo& args) { uv_uid_t uid = static_cast(args[1]->Uint32Value()); uv_gid_t gid = static_cast(args[2]->Uint32Value()); - if (args[3]->IsFunction()) { + if (args[3]->IsObject()) { ASYNC_CALL(chown, args[3], *path, uid, gid); } else { SYNC_CALL(chown, *path, *path, uid, gid); @@ -1047,7 +1056,7 @@ static void FChown(const FunctionCallbackInfo& args) { uv_uid_t uid = static_cast(args[1]->Uint32Value()); uv_gid_t gid = static_cast(args[2]->Uint32Value()); - if (args[3]->IsFunction()) { + if (args[3]->IsObject()) { ASYNC_CALL(fchown, args[3], fd, uid, gid); } else { SYNC_CALL(fchown, 0, fd, uid, gid); @@ -1077,7 +1086,7 @@ static void UTimes(const FunctionCallbackInfo& args) { const double atime = static_cast(args[1]->NumberValue()); const double mtime = static_cast(args[2]->NumberValue()); - if (args[3]->IsFunction()) { + if (args[3]->IsObject()) { ASYNC_CALL(utime, args[3], *path, atime, mtime); } else { SYNC_CALL(utime, *path, *path, atime, mtime); @@ -1106,7 +1115,7 @@ static void FUTimes(const FunctionCallbackInfo& args) { const double atime = static_cast(args[1]->NumberValue()); const double mtime = static_cast(args[2]->NumberValue()); - if (args[3]->IsFunction()) { + if (args[3]->IsObject()) { ASYNC_CALL(futime, args[3], fd, atime, mtime); } else { SYNC_CALL(futime, 0, fd, atime, mtime); @@ -1164,6 +1173,14 @@ void InitFs(Handle target, NODE_SET_METHOD(target, "futimes", FUTimes); StatWatcher::Initialize(env, target); + + // Create FunctionTemplate for FSReqWrap + Local fst = + FunctionTemplate::New(env->isolate(), NewFSReqWrap); + fst->InstanceTemplate()->SetInternalFieldCount(1); + fst->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "FSReqWrap")); + target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "FSReqWrap"), + fst->GetFunction()); } } // end namespace node diff --git a/src/pipe_wrap.cc b/src/pipe_wrap.cc index 05472de5d92d..69cdfcdff3cf 100644 --- a/src/pipe_wrap.cc +++ b/src/pipe_wrap.cc @@ -21,6 +21,7 @@ #include "pipe_wrap.h" +#include "async-wrap.h" #include "env.h" #include "env-inl.h" #include "handle_wrap.h" @@ -37,6 +38,7 @@ namespace node { using v8::Boolean; using v8::Context; using v8::EscapableHandleScope; +using v8::External; using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; @@ -50,8 +52,23 @@ using v8::String; using v8::Undefined; using v8::Value; + // TODO(bnoordhuis) share with TCPWrap? -typedef class ReqWrap ConnectWrap; +class PipeConnectWrap : public ReqWrap { + public: + PipeConnectWrap(Environment* env, Local req_wrap_obj); +}; + + +PipeConnectWrap::PipeConnectWrap(Environment* env, Local req_wrap_obj) + : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_PIPEWRAP) { + Wrap(req_wrap_obj, this); +} + + +static void NewPipeConnectWrap(const FunctionCallbackInfo& args) { + CHECK(args.IsConstructCall()); +} uv_pipe_t* PipeWrap::UVHandle() { @@ -59,12 +76,13 @@ uv_pipe_t* PipeWrap::UVHandle() { } -Local PipeWrap::Instantiate(Environment* env) { +Local PipeWrap::Instantiate(Environment* env, AsyncWrap* parent) { EscapableHandleScope handle_scope(env->isolate()); assert(!env->pipe_constructor_template().IsEmpty()); Local constructor = env->pipe_constructor_template()->GetFunction(); assert(!constructor.IsEmpty()); - Local instance = constructor->NewInstance(); + Local ptr = External::New(env->isolate(), parent); + Local instance = constructor->NewInstance(1, &ptr); assert(!instance.IsEmpty()); return handle_scope.Escape(instance); } @@ -119,6 +137,14 @@ void PipeWrap::Initialize(Handle target, target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "Pipe"), t->GetFunction()); env->set_pipe_constructor_template(t); + + // Create FunctionTemplate for PipeConnectWrap. + Local cwt = + FunctionTemplate::New(env->isolate(), NewPipeConnectWrap); + cwt->InstanceTemplate()->SetInternalFieldCount(1); + cwt->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "PipeConnectWrap")); + target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "PipeConnectWrap"), + cwt->GetFunction()); } @@ -127,17 +153,25 @@ void PipeWrap::New(const FunctionCallbackInfo& args) { // Therefore we assert that we are not trying to call this as a // normal function. assert(args.IsConstructCall()); - HandleScope handle_scope(args.GetIsolate()); Environment* env = Environment::GetCurrent(args.GetIsolate()); - new PipeWrap(env, args.This(), args[0]->IsTrue()); + if (args[0]->IsExternal()) { + void* ptr = args[0].As()->Value(); + new PipeWrap(env, args.This(), false, static_cast(ptr)); + } else { + new PipeWrap(env, args.This(), args[0]->IsTrue(), NULL); + } } -PipeWrap::PipeWrap(Environment* env, Handle object, bool ipc) +PipeWrap::PipeWrap(Environment* env, + Handle object, + bool ipc, + AsyncWrap* parent) : StreamWrap(env, object, reinterpret_cast(&handle_), - AsyncWrap::PROVIDER_PIPEWRAP) { + AsyncWrap::PROVIDER_PIPEWRAP, + parent) { int r = uv_pipe_init(env->event_loop(), &handle_, ipc); assert(r == 0); // How do we proxy this error up to javascript? // Suggestion: uv_pipe_init() returns void. @@ -209,7 +243,7 @@ void PipeWrap::OnConnection(uv_stream_t* handle, int status) { } // Instanciate the client javascript object and handle. - Local client_obj = Instantiate(env); + Local client_obj = Instantiate(env, pipe_wrap); // Unwrap the client javascript object. PipeWrap* wrap = Unwrap(client_obj); @@ -224,7 +258,7 @@ void PipeWrap::OnConnection(uv_stream_t* handle, int status) { // TODO(bnoordhuis) Maybe share this with TCPWrap? void PipeWrap::AfterConnect(uv_connect_t* req, int status) { - ConnectWrap* req_wrap = static_cast(req->data); + PipeConnectWrap* req_wrap = static_cast(req->data); PipeWrap* wrap = static_cast(req->handle->data); assert(req_wrap->env() == wrap->env()); Environment* env = wrap->env(); @@ -287,9 +321,7 @@ void PipeWrap::Connect(const FunctionCallbackInfo& args) { Local req_wrap_obj = args[0].As(); node::Utf8Value name(args[1]); - ConnectWrap* req_wrap = new ConnectWrap(env, - req_wrap_obj, - AsyncWrap::PROVIDER_CONNECTWRAP); + PipeConnectWrap* req_wrap = new PipeConnectWrap(env, req_wrap_obj); uv_pipe_connect(&req_wrap->req_, &wrap->handle_, *name, diff --git a/src/pipe_wrap.h b/src/pipe_wrap.h index 92492c42b73c..959f28f4dca9 100644 --- a/src/pipe_wrap.h +++ b/src/pipe_wrap.h @@ -22,6 +22,7 @@ #ifndef SRC_PIPE_WRAP_H_ #define SRC_PIPE_WRAP_H_ +#include "async-wrap.h" #include "env.h" #include "stream_wrap.h" @@ -31,13 +32,16 @@ class PipeWrap : public StreamWrap { public: uv_pipe_t* UVHandle(); - static v8::Local Instantiate(Environment* env); + static v8::Local Instantiate(Environment* env, AsyncWrap* parent); static void Initialize(v8::Handle target, v8::Handle unused, v8::Handle context); private: - PipeWrap(Environment* env, v8::Handle object, bool ipc); + PipeWrap(Environment* env, + v8::Handle object, + bool ipc, + AsyncWrap* parent); static void New(const v8::FunctionCallbackInfo& args); static void Bind(const v8::FunctionCallbackInfo& args); diff --git a/src/req_wrap.h b/src/req_wrap.h index df4ed2ced1a8..8c818e634a83 100644 --- a/src/req_wrap.h +++ b/src/req_wrap.h @@ -36,8 +36,8 @@ class ReqWrap : public AsyncWrap { public: ReqWrap(Environment* env, v8::Handle object, - AsyncWrap::ProviderType provider = AsyncWrap::PROVIDER_REQWRAP) - : AsyncWrap(env, object, AsyncWrap::PROVIDER_REQWRAP) { + AsyncWrap::ProviderType provider) + : AsyncWrap(env, object, provider) { if (env->in_domain()) object->Set(env->domain_string(), env->domain_array()->Get(0)); diff --git a/src/stream_wrap.cc b/src/stream_wrap.cc index fe3e82799dfa..840b16614a13 100644 --- a/src/stream_wrap.cc +++ b/src/stream_wrap.cc @@ -43,6 +43,7 @@ using v8::Array; using v8::Context; using v8::EscapableHandleScope; using v8::FunctionCallbackInfo; +using v8::FunctionTemplate; using v8::Handle; using v8::HandleScope; using v8::Integer; @@ -56,11 +57,37 @@ using v8::Undefined; using v8::Value; +void StreamWrap::Initialize(Handle target, + Handle unused, + Handle context) { + Environment* env = Environment::GetCurrent(context); + + Local sw = + FunctionTemplate::New(env->isolate(), ShutdownWrap::NewShutdownWrap); + sw->InstanceTemplate()->SetInternalFieldCount(1); + sw->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "ShutdownWrap")); + target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "ShutdownWrap"), + sw->GetFunction()); + + Local ww = + FunctionTemplate::New(env->isolate(), WriteWrap::NewWriteWrap); + ww->InstanceTemplate()->SetInternalFieldCount(1); + ww->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "WriteWrap")); + target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "WriteWrap"), + ww->GetFunction()); +} + + StreamWrap::StreamWrap(Environment* env, Local object, uv_stream_t* stream, - AsyncWrap::ProviderType provider) - : HandleWrap(env, object, reinterpret_cast(stream), provider), + AsyncWrap::ProviderType provider, + AsyncWrap* parent) + : HandleWrap(env, + object, + reinterpret_cast(stream), + provider, + parent), stream_(stream), default_callbacks_(this), callbacks_(&default_callbacks_), @@ -89,6 +116,7 @@ void StreamWrap::UpdateWriteQueueSize() { object()->Set(env()->write_queue_size_string(), write_queue_size); } + void StreamWrap::ReadStart(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args.GetIsolate()); HandleScope scope(env->isolate()); @@ -122,12 +150,14 @@ void StreamWrap::OnAlloc(uv_handle_t* handle, template -static Local AcceptHandle(Environment* env, uv_stream_t* pipe) { +static Local AcceptHandle(Environment* env, + uv_stream_t* pipe, + AsyncWrap* parent) { EscapableHandleScope scope(env->isolate()); Local wrap_obj; UVType* handle; - wrap_obj = WrapType::Instantiate(env); + wrap_obj = WrapType::Instantiate(env, parent); if (wrap_obj.IsEmpty()) return Local(); @@ -560,9 +590,7 @@ void StreamWrap::Shutdown(const FunctionCallbackInfo& args) { assert(args[0]->IsObject()); Local req_wrap_obj = args[0].As(); - ShutdownWrap* req_wrap = new ShutdownWrap(env, - req_wrap_obj, - AsyncWrap::PROVIDER_SHUTDOWNWRAP); + ShutdownWrap* req_wrap = new ShutdownWrap(env, req_wrap_obj); int err = wrap->callbacks()->DoShutdown(req_wrap, AfterShutdown); req_wrap->Dispatched(); if (err) @@ -722,11 +750,11 @@ void StreamWrapCallbacks::DoRead(uv_stream_t* handle, Local pending_obj; if (pending == UV_TCP) { - pending_obj = AcceptHandle(env, handle); + pending_obj = AcceptHandle(env, handle, wrap()); } else if (pending == UV_NAMED_PIPE) { - pending_obj = AcceptHandle(env, handle); + pending_obj = AcceptHandle(env, handle, wrap()); } else if (pending == UV_UDP) { - pending_obj = AcceptHandle(env, handle); + pending_obj = AcceptHandle(env, handle, wrap()); } else { assert(pending == UV_UNKNOWN_HANDLE); } @@ -744,3 +772,5 @@ int StreamWrapCallbacks::DoShutdown(ShutdownWrap* req_wrap, uv_shutdown_cb cb) { } } // namespace node + +NODE_MODULE_CONTEXT_AWARE_BUILTIN(stream_wrap, node::StreamWrap::Initialize) diff --git a/src/stream_wrap.h b/src/stream_wrap.h index 34e2799357d2..38e5d4842257 100644 --- a/src/stream_wrap.h +++ b/src/stream_wrap.h @@ -33,15 +33,26 @@ namespace node { // Forward declaration class StreamWrap; -typedef class ReqWrap ShutdownWrap; +class ShutdownWrap : public ReqWrap { + public: + ShutdownWrap(Environment* env, v8::Local req_wrap_obj) + : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_SHUTDOWNWRAP) { + Wrap(req_wrap_obj, this); + } + + static void NewShutdownWrap(const v8::FunctionCallbackInfo& args) { + CHECK(args.IsConstructCall()); + } +}; class WriteWrap: public ReqWrap { public: // TODO(trevnorris): WrapWrap inherits from ReqWrap, which I've globbed // into the same provider. How should these be broken apart? WriteWrap(Environment* env, v8::Local obj, StreamWrap* wrap) - : ReqWrap(env, obj), + : ReqWrap(env, obj, AsyncWrap::PROVIDER_WRITEWRAP), wrap_(wrap) { + Wrap(obj, this); } void* operator new(size_t size, char* storage) { return storage; } @@ -54,6 +65,10 @@ class WriteWrap: public ReqWrap { return wrap_; } + static void NewWriteWrap(const v8::FunctionCallbackInfo& args) { + CHECK(args.IsConstructCall()); + } + private: // People should not be using the non-placement new and delete operator on a // WriteWrap. Ensure this never happens. @@ -105,6 +120,10 @@ class StreamWrapCallbacks { class StreamWrap : public HandleWrap { public: + static void Initialize(v8::Handle target, + v8::Handle unused, + v8::Handle context); + void OverrideCallbacks(StreamWrapCallbacks* callbacks, bool gc) { StreamWrapCallbacks* old = callbacks_; callbacks_ = callbacks; @@ -158,7 +177,8 @@ class StreamWrap : public HandleWrap { StreamWrap(Environment* env, v8::Local object, uv_stream_t* stream, - AsyncWrap::ProviderType provider); + AsyncWrap::ProviderType provider, + AsyncWrap* parent = NULL); ~StreamWrap() { if (!callbacks_gc_ && callbacks_ != &default_callbacks_) { diff --git a/src/tcp_wrap.cc b/src/tcp_wrap.cc index 09671d0095e2..a5b20a6ac5a6 100644 --- a/src/tcp_wrap.cc +++ b/src/tcp_wrap.cc @@ -38,6 +38,7 @@ namespace node { using v8::Context; using v8::EscapableHandleScope; +using v8::External; using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; @@ -52,15 +53,31 @@ using v8::Undefined; using v8::Value; using v8::Boolean; -typedef class ReqWrap ConnectWrap; +class TCPConnectWrap : public ReqWrap { + public: + TCPConnectWrap(Environment* env, Local req_wrap_obj); +}; -Local TCPWrap::Instantiate(Environment* env) { + +TCPConnectWrap::TCPConnectWrap(Environment* env, Local req_wrap_obj) + : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_TCPWRAP) { + Wrap(req_wrap_obj, this); +} + + +static void NewTCPConnectWrap(const FunctionCallbackInfo& args) { + CHECK(args.IsConstructCall()); +} + + +Local TCPWrap::Instantiate(Environment* env, AsyncWrap* parent) { EscapableHandleScope handle_scope(env->isolate()); assert(env->tcp_constructor_template().IsEmpty() == false); Local constructor = env->tcp_constructor_template()->GetFunction(); assert(constructor.IsEmpty() == false); - Local instance = constructor->NewInstance(); + Local ptr = External::New(env->isolate(), parent); + Local instance = constructor->NewInstance(1, &ptr); assert(instance.IsEmpty() == false); return handle_scope.Escape(instance); } @@ -135,6 +152,14 @@ void TCPWrap::Initialize(Handle target, target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "TCP"), t->GetFunction()); env->set_tcp_constructor_template(t); + + // Create FunctionTemplate for TCPConnectWrap. + Local cwt = + FunctionTemplate::New(env->isolate(), NewTCPConnectWrap); + cwt->InstanceTemplate()->SetInternalFieldCount(1); + cwt->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "TCPConnectWrap")); + target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "TCPConnectWrap"), + cwt->GetFunction()); } @@ -148,18 +173,26 @@ void TCPWrap::New(const FunctionCallbackInfo& args) { // Therefore we assert that we are not trying to call this as a // normal function. assert(args.IsConstructCall()); - HandleScope handle_scope(args.GetIsolate()); Environment* env = Environment::GetCurrent(args.GetIsolate()); - TCPWrap* wrap = new TCPWrap(env, args.This()); + TCPWrap* wrap; + if (args.Length() == 0) { + wrap = new TCPWrap(env, args.This(), NULL); + } else if (args[0]->IsExternal()) { + void* ptr = args[0].As()->Value(); + wrap = new TCPWrap(env, args.This(), static_cast(ptr)); + } else { + UNREACHABLE(); + } assert(wrap); } -TCPWrap::TCPWrap(Environment* env, Handle object) +TCPWrap::TCPWrap(Environment* env, Handle object, AsyncWrap* parent) : StreamWrap(env, object, reinterpret_cast(&handle_), - AsyncWrap::PROVIDER_TCPWRAP) { + AsyncWrap::PROVIDER_TCPWRAP, + parent) { int r = uv_tcp_init(env->event_loop(), &handle_); assert(r == 0); // How do we proxy this error up to javascript? // Suggestion: uv_tcp_init() returns void. @@ -342,7 +375,8 @@ void TCPWrap::OnConnection(uv_stream_t* handle, int status) { if (status == 0) { // Instantiate the client javascript object and handle. - Local client_obj = Instantiate(env); + Local client_obj = + Instantiate(env, static_cast(tcp_wrap)); // Unwrap the client javascript object. TCPWrap* wrap = Unwrap(client_obj); @@ -359,7 +393,7 @@ void TCPWrap::OnConnection(uv_stream_t* handle, int status) { void TCPWrap::AfterConnect(uv_connect_t* req, int status) { - ConnectWrap* req_wrap = static_cast(req->data); + TCPConnectWrap* req_wrap = static_cast(req->data); TCPWrap* wrap = static_cast(req->handle->data); assert(req_wrap->env() == wrap->env()); Environment* env = wrap->env(); @@ -404,9 +438,7 @@ void TCPWrap::Connect(const FunctionCallbackInfo& args) { int err = uv_ip4_addr(*ip_address, port, &addr); if (err == 0) { - ConnectWrap* req_wrap = new ConnectWrap(env, - req_wrap_obj, - AsyncWrap::PROVIDER_CONNECTWRAP); + TCPConnectWrap* req_wrap = new TCPConnectWrap(env, req_wrap_obj); err = uv_tcp_connect(&req_wrap->req_, &wrap->handle_, reinterpret_cast(&addr), @@ -438,9 +470,7 @@ void TCPWrap::Connect6(const FunctionCallbackInfo& args) { int err = uv_ip6_addr(*ip_address, port, &addr); if (err == 0) { - ConnectWrap* req_wrap = new ConnectWrap(env, - req_wrap_obj, - AsyncWrap::PROVIDER_CONNECTWRAP); + TCPConnectWrap* req_wrap = new TCPConnectWrap(env, req_wrap_obj); err = uv_tcp_connect(&req_wrap->req_, &wrap->handle_, reinterpret_cast(&addr), diff --git a/src/tcp_wrap.h b/src/tcp_wrap.h index c9981f572dbe..c923b387f0e7 100644 --- a/src/tcp_wrap.h +++ b/src/tcp_wrap.h @@ -22,6 +22,7 @@ #ifndef SRC_TCP_WRAP_H_ #define SRC_TCP_WRAP_H_ +#include "async-wrap.h" #include "env.h" #include "stream_wrap.h" @@ -29,7 +30,7 @@ namespace node { class TCPWrap : public StreamWrap { public: - static v8::Local Instantiate(Environment* env); + static v8::Local Instantiate(Environment* env, AsyncWrap* parent); static void Initialize(v8::Handle target, v8::Handle unused, v8::Handle context); @@ -37,7 +38,7 @@ class TCPWrap : public StreamWrap { uv_tcp_t* UVHandle(); private: - TCPWrap(Environment* env, v8::Handle object); + TCPWrap(Environment* env, v8::Handle object, AsyncWrap* parent); ~TCPWrap(); static void New(const v8::FunctionCallbackInfo& args); diff --git a/src/tls_wrap.cc b/src/tls_wrap.cc index ac05c8ecaceb..607f786501e3 100644 --- a/src/tls_wrap.cc +++ b/src/tls_wrap.cc @@ -78,7 +78,7 @@ TLSCallbacks::TLSCallbacks(Environment* env, error_(NULL), cycle_depth_(0), eof_(false) { - node::Wrap(object(), this); + node::Wrap(object(), this); MakeWeak(this); // Initialize queue for clearIn writes diff --git a/src/udp_wrap.cc b/src/udp_wrap.cc index f0d491333976..614326fa1fb9 100644 --- a/src/udp_wrap.cc +++ b/src/udp_wrap.cc @@ -34,6 +34,8 @@ namespace node { using v8::Context; +using v8::EscapableHandleScope; +using v8::External; using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; @@ -62,8 +64,9 @@ class SendWrap : public ReqWrap { SendWrap::SendWrap(Environment* env, Local req_wrap_obj, bool have_callback) - : ReqWrap(env, req_wrap_obj), + : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_UDPWRAP), have_callback_(have_callback) { + Wrap(req_wrap_obj, this); } @@ -72,7 +75,12 @@ inline bool SendWrap::have_callback() const { } -UDPWrap::UDPWrap(Environment* env, Handle object) +static void NewSendWrap(const FunctionCallbackInfo& args) { + assert(args.IsConstructCall()); +} + + +UDPWrap::UDPWrap(Environment* env, Handle object, AsyncWrap* parent) : HandleWrap(env, object, reinterpret_cast(&handle_), @@ -124,14 +132,29 @@ void UDPWrap::Initialize(Handle target, target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "UDP"), t->GetFunction()); env->set_udp_constructor_function(t->GetFunction()); + + // Create FunctionTemplate for SendWrap + Local swt = + FunctionTemplate::New(env->isolate(), NewSendWrap); + swt->InstanceTemplate()->SetInternalFieldCount(1); + swt->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "SendWrap")); + target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "SendWrap"), + swt->GetFunction()); } void UDPWrap::New(const FunctionCallbackInfo& args) { - assert(args.IsConstructCall()); - HandleScope handle_scope(args.GetIsolate()); + CHECK(args.IsConstructCall()); Environment* env = Environment::GetCurrent(args.GetIsolate()); - new UDPWrap(env, args.This()); + if (args.Length() == 0) { + new UDPWrap(env, args.This(), NULL); + } else if (args[0]->IsExternal()) { + new UDPWrap(env, + args.This(), + static_cast(args[0].As()->Value())); + } else { + UNREACHABLE(); + } } @@ -429,10 +452,12 @@ void UDPWrap::OnRecv(uv_udp_t* handle, } -Local UDPWrap::Instantiate(Environment* env) { +Local UDPWrap::Instantiate(Environment* env, AsyncWrap* parent) { // If this assert fires then Initialize hasn't been called yet. assert(env->udp_constructor_function().IsEmpty() == false); - return env->udp_constructor_function()->NewInstance(); + EscapableHandleScope scope(env->isolate()); + Local ptr = External::New(env->isolate(), parent); + return scope.Escape(env->udp_constructor_function()->NewInstance(1, &ptr)); } diff --git a/src/udp_wrap.h b/src/udp_wrap.h index ab0d6fa8e69e..693fa51b7180 100644 --- a/src/udp_wrap.h +++ b/src/udp_wrap.h @@ -22,6 +22,7 @@ #ifndef SRC_UDP_WRAP_H_ #define SRC_UDP_WRAP_H_ +#include "async-wrap.h" #include "env.h" #include "handle_wrap.h" #include "req_wrap.h" @@ -53,11 +54,11 @@ class UDPWrap: public HandleWrap { static void SetBroadcast(const v8::FunctionCallbackInfo& args); static void SetTTL(const v8::FunctionCallbackInfo& args); - static v8::Local Instantiate(Environment* env); + static v8::Local Instantiate(Environment* env, AsyncWrap* parent); uv_udp_t* UVHandle(); private: - UDPWrap(Environment* env, v8::Handle object); + UDPWrap(Environment* env, v8::Handle object, AsyncWrap* parent); virtual ~UDPWrap(); static void DoBind(const v8::FunctionCallbackInfo& args, diff --git a/test/internet/test-dns.js b/test/internet/test-dns.js index 60227df7ca67..623a845c03f3 100644 --- a/test/internet/test-dns.js +++ b/test/internet/test-dns.js @@ -632,8 +632,9 @@ var getaddrinfoCallbackCalled = false; console.log('looking up nodejs.org...'); -var req = {}; -var err = process.binding('cares_wrap').getaddrinfo(req, 'nodejs.org', 4); +var cares = process.binding('cares_wrap'); +var req = new cares.GetAddrInfoReqWrap(); +var err = cares.getaddrinfo(req, 'nodejs.org', 4); req.oncomplete = function(err, domains) { assert.strictEqual(err, 0); diff --git a/test/simple/test-asynclistener-error-multiple-handled.js b/test/simple/test-asynclistener-error-multiple-handled.js deleted file mode 100644 index 576ce58e4cf3..000000000000 --- a/test/simple/test-asynclistener-error-multiple-handled.js +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var tracing = require('tracing'); - -var active = null; -var cntr = 0; - -function onAsync0() { - return 0; -} - -function onAsync1() { - return 1; -} - -function onError(stor) { - results.push(stor); - return true; -} - -var results = []; -var asyncNoHandleError0 = { - create: onAsync0, - error: onError -}; -var asyncNoHandleError1 = { - create: onAsync1, - error: onError -}; - -var listeners = [ - tracing.addAsyncListener(asyncNoHandleError0), - tracing.addAsyncListener(asyncNoHandleError1) -]; - -process.nextTick(function() { - throw new Error(); -}); - -tracing.removeAsyncListener(listeners[0]); -tracing.removeAsyncListener(listeners[1]); - -process.on('exit', function(code) { - // If the exit code isn't ok then return early to throw the stack that - // caused the bad return code. - if (code !== 0) - return; - - // Handling of errors should propagate to all listeners. - assert.equal(results[0], 0); - assert.equal(results[1], 1); - assert.equal(results.length, 2); - - console.log('ok'); -}); diff --git a/test/simple/test-asynclistener-error-multiple-mix.js b/test/simple/test-asynclistener-error-multiple-mix.js deleted file mode 100644 index 83716bc281c8..000000000000 --- a/test/simple/test-asynclistener-error-multiple-mix.js +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var tracing = require('tracing'); - -var results = []; -var asyncNoHandleError = { - error: function(stor) { - results.push(1); - } -}; - -var asyncHandleError = { - error: function(stor) { - results.push(0); - return true; - } -}; - -var listeners = [ - tracing.addAsyncListener(asyncHandleError), - tracing.addAsyncListener(asyncNoHandleError) -]; - -// Even if an error handler returns true, both should fire. -process.nextTick(function() { - throw new Error(); -}); - -tracing.removeAsyncListener(listeners[0]); -tracing.removeAsyncListener(listeners[1]); - -process.on('exit', function(code) { - // If the exit code isn't ok then return early to throw the stack that - // caused the bad return code. - if (code !== 0) - return; - - // Mixed handling of errors should propagate to all listeners. - assert.equal(results[0], 0); - assert.equal(results[1], 1); - assert.equal(results.length, 2); - - console.log('ok'); -}); diff --git a/test/simple/test-asynclistener-error-multiple-unhandled.js b/test/simple/test-asynclistener-error-multiple-unhandled.js deleted file mode 100644 index 33afaaa81b14..000000000000 --- a/test/simple/test-asynclistener-error-multiple-unhandled.js +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var tracing = require('tracing'); - -function onAsync0() { - return 0; -} - -function onAsync1() { - return 1; -} - -function onError(stor) { - results.push(stor); -} - -var results = []; -var asyncNoHandleError0 = { - create: onAsync0, - error: onError -}; -var asyncNoHandleError1 = { - create: onAsync1, - error: onError -}; - -var listeners = [ - tracing.addAsyncListener(asyncNoHandleError0), - tracing.addAsyncListener(asyncNoHandleError1) -]; - -var uncaughtFired = false; -process.on('uncaughtException', function() { - uncaughtFired = true; - - // Unhandled errors should propagate to all listeners. - assert.equal(results[0], 0); - assert.equal(results[1], 1); - assert.equal(results.length, 2); -}); - -process.nextTick(function() { - throw new Error(); -}); - -process.on('exit', function(code) { - // If the exit code isn't ok then return early to throw the stack that - // caused the bad return code. - if (code !== 0) - return; - - // Need to remove the async listeners or tests will always pass - for (var i = 0; i < listeners.length; i++) - tracing.removeAsyncListener(listeners[i]); - - assert.ok(uncaughtFired); - console.log('ok'); -}); diff --git a/test/simple/test-asynclistener-error-net.js b/test/simple/test-asynclistener-error-net.js deleted file mode 100644 index 26a337a5044e..000000000000 --- a/test/simple/test-asynclistener-error-net.js +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var dns = require('dns'); -var fs = require('fs'); -var net = require('net'); -var tracing = require('tracing'); - -var errorMsgs = []; -var caught = 0; -var expectCaught = 0; - -var callbacksObj = { - error: function(value, er) { - var idx = errorMsgs.indexOf(er.message); - caught++; - - process._rawDebug('Handling error: ' + er.message); - - if (-1 < idx) - errorMsgs.splice(idx, 1); - else - throw new Error('Message not found: ' + er.message); - - return true; - } -}; - -var listener = tracing.addAsyncListener(callbacksObj); - -process.on('exit', function(code) { - tracing.removeAsyncListener(listener); - - if (code > 0) - return; - - if (errorMsgs.length > 0) - throw new Error('Errors not fired: ' + errorMsgs); - - assert.equal(caught, expectCaught); - process._rawDebug('ok'); -}); - - -// Net -var iter = 3; -for (var i = 0; i < iter; i++) { - errorMsgs.push('net - error: server connection'); - errorMsgs.push('net - error: client data'); - errorMsgs.push('net - error: server data'); -} -errorMsgs.push('net - error: server closed'); - -var server = net.createServer(function(c) { - c.on('data', function() { - if (0 === --iter) { - server.close(function() { - process._rawDebug('net - server closing'); - throw new Error('net - error: server closed'); - }); - expectCaught++; - } - process._rawDebug('net - connection received data'); - throw new Error('net - error: server data'); - }); - expectCaught++; - - c.end('bye'); - process._rawDebug('net - connection received'); - throw new Error('net - error: server connection'); -}); -expectCaught += iter; - -server.listen(common.PORT, function() { - for (var i = 0; i < iter; i++) - clientConnect(); -}); - -function clientConnect() { - var client = net.connect(common.PORT, function() { }); - - client.on('data', function() { - client.end('see ya'); - process._rawDebug('net - client received data'); - throw new Error('net - error: client data'); - }); - expectCaught++; -} diff --git a/test/simple/test-asynclistener-error-throw-in-after.js b/test/simple/test-asynclistener-error-throw-in-after.js deleted file mode 100644 index 3eb02e165d49..000000000000 --- a/test/simple/test-asynclistener-error-throw-in-after.js +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var tracing = require('tracing'); - -var once = 0; - -var results = []; -var handlers = { - after: function() { - throw 1; - }, - error: function(stor, err) { - // Error handler must be called exactly *once*. - once++; - assert.equal(err, 1); - return true; - } -} - -var key = tracing.addAsyncListener(handlers); - -var uncaughtFired = false; -process.on('uncaughtException', function(err) { - uncaughtFired = true; - - assert.equal(once, 1); -}); - -process.nextTick(function() { }); - -tracing.removeAsyncListener(key); - -process.on('exit', function(code) { - // If the exit code isn't ok then return early to throw the stack that - // caused the bad return code. - if (code !== 0) - return; - - assert.ok(uncaughtFired); - console.log('ok'); -}); diff --git a/test/simple/test-asynclistener-error-throw-in-before-multiple.js b/test/simple/test-asynclistener-error-throw-in-before-multiple.js deleted file mode 100644 index b9aecf3977b3..000000000000 --- a/test/simple/test-asynclistener-error-throw-in-before-multiple.js +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var tracing = require('tracing'); - -var once = 0; - -var results = []; -var handlers = { - before: function() { - throw 1; - }, - error: function(stor, err) { - // Must catch error thrown in before callback. - assert.equal(err, 1); - once++; - return true; - } -} - -var handlers1 = { - before: function() { - throw 2; - }, - error: function(stor, err) { - // Must catch *other* handlers throw by error callback. - assert.equal(err, 1); - once++; - return true; - } -} - -var listeners = [ - tracing.addAsyncListener(handlers), - tracing.addAsyncListener(handlers1) -]; - -var uncaughtFired = false; -process.on('uncaughtException', function(err) { - uncaughtFired = true; - - // Both error handlers must fire. - assert.equal(once, 2); -}); - -process.nextTick(function() { }); - -for (var i = 0; i < listeners.length; i++) - tracing.removeAsyncListener(listeners[i]); - -process.on('exit', function(code) { - // If the exit code isn't ok then return early to throw the stack that - // caused the bad return code. - if (code !== 0) - return; - // Make sure uncaughtException actually fired. - assert.ok(uncaughtFired); - console.log('ok'); -}); - diff --git a/test/simple/test-asynclistener-error-throw-in-before.js b/test/simple/test-asynclistener-error-throw-in-before.js deleted file mode 100644 index fb6b6eeecaed..000000000000 --- a/test/simple/test-asynclistener-error-throw-in-before.js +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var tracing = require('tracing'); - -var once = 0; - -var results = []; -var handlers = { - before: function() { - throw 1; - }, - error: function(stor, err) { - // Error handler must be called exactly *once*. - once++; - assert.equal(err, 1); - return true; - } -} - -var key = tracing.addAsyncListener(handlers); - -var uncaughtFired = false; -process.on('uncaughtException', function(err) { - uncaughtFired = true; - - // Process should propagate error regardless of handlers return value. - assert.equal(once, 1); -}); - -process.nextTick(function() { }); - -tracing.removeAsyncListener(key); - -process.on('exit', function(code) { - // If the exit code isn't ok then return early to throw the stack that - // caused the bad return code. - if (code !== 0) - return; - - // Make sure that the uncaughtException actually fired. - assert.ok(uncaughtFired); - console.log('ok'); -}); diff --git a/test/simple/test-asynclistener-error-throw-in-error.js b/test/simple/test-asynclistener-error-throw-in-error.js deleted file mode 100644 index c66d688fbea8..000000000000 --- a/test/simple/test-asynclistener-error-throw-in-error.js +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var spawn = require('child_process').spawn; -var tracing = require('tracing'); - -var checkStr = 'WRITTEN ON EXIT'; - -if (process.argv[2] === 'child') - runChild(); -else - runParent(); - - -function runChild() { - var cntr = 0; - - var key = tracing.addAsyncListener({ - error: function onError() { - cntr++; - throw new Error('onError'); - } - }); - - process.on('unhandledException', function() { - // Throwing in 'error' should bypass unhandledException. - process.exit(2); - }); - - process.on('exit', function() { - // Make sure that we can still write out to stderr even when the - // process dies. - process._rawDebug(checkStr); - }); - - process.nextTick(function() { - throw new Error('nextTick'); - }); -} - - -function runParent() { - var childDidExit = false; - var childStr = ''; - var child = spawn(process.execPath, [__filename, 'child']); - child.stderr.on('data', function(chunk) { - process._rawDebug('received data from child'); - childStr += chunk.toString(); - }); - - child.on('exit', function(code) { - process._rawDebug('child process exiting'); - childDidExit = true; - // This is thrown when Node throws from _fatalException. - assert.equal(code, 7); - }); - - process.on('exit', function() { - process._rawDebug('child ondata message:', - childStr.substr(0, checkStr.length)); - - assert.ok(childDidExit); - assert.equal(childStr.substr(0, checkStr.length), checkStr); - console.log('ok'); - }); -} - diff --git a/test/simple/test-asynclistener-error.js b/test/simple/test-asynclistener-error.js deleted file mode 100644 index 6e5f31b0348c..000000000000 --- a/test/simple/test-asynclistener-error.js +++ /dev/null @@ -1,257 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var dns = require('dns'); -var fs = require('fs'); -var net = require('net'); -var tracing = require('tracing'); - -var addListener = tracing.addAsyncListener; -var removeListener = tracing.removeAsyncListener; -var errorMsgs = []; -var currentMsg = ''; -var caught = 0; -var expectCaught = 0; -var exitCbRan = false; - -var callbacksObj = { - error: function(value, er) { - var idx = errorMsgs.indexOf(er.message); - - caught++; - - if (-1 < idx) - errorMsgs.splice(idx, 1); - - return currentMsg === er.message; - } -}; - -var listener = tracing.createAsyncListener(callbacksObj); - -process.on('exit', function(code) { - removeListener(listener); - - // Something else went wrong, no need to further check. - if (code > 0) - return; - - // Make sure the exit callback only runs once. - assert.ok(!exitCbRan); - exitCbRan = true; - - // Check if any error messages weren't removed from the msg queue. - if (errorMsgs.length > 0) - throw new Error('Errors not fired: ' + errorMsgs); - - assert.equal(caught, expectCaught, 'caught all expected errors'); - process._rawDebug('ok'); -}); - - -// Catch synchronous throws -errorMsgs.push('sync throw'); -process.nextTick(function() { - addListener(listener); - - expectCaught++; - currentMsg = 'sync throw'; - throw new Error(currentMsg); - - removeListener(listener); -}); - - -// Simple cases -errorMsgs.push('setTimeout - simple'); -errorMsgs.push('setImmediate - simple'); -errorMsgs.push('setInterval - simple'); -errorMsgs.push('process.nextTick - simple'); -process.nextTick(function() { - addListener(listener); - - setTimeout(function() { - currentMsg = 'setTimeout - simple'; - throw new Error(currentMsg); - }); - expectCaught++; - - setImmediate(function() { - currentMsg = 'setImmediate - simple'; - throw new Error(currentMsg); - }); - expectCaught++; - - var b = setInterval(function() { - clearInterval(b); - currentMsg = 'setInterval - simple'; - throw new Error(currentMsg); - }); - expectCaught++; - - process.nextTick(function() { - currentMsg = 'process.nextTick - simple'; - throw new Error(currentMsg); - }); - expectCaught++; - - removeListener(listener); -}); - - -// Deeply nested -errorMsgs.push('setInterval - nested'); -errorMsgs.push('setImmediate - nested'); -errorMsgs.push('process.nextTick - nested'); -errorMsgs.push('setTimeout2 - nested'); -errorMsgs.push('setTimeout - nested'); -process.nextTick(function() { - addListener(listener); - - setTimeout(function() { - process.nextTick(function() { - setImmediate(function() { - var b = setInterval(function() { - clearInterval(b); - currentMsg = 'setInterval - nested'; - throw new Error(currentMsg); - }); - expectCaught++; - currentMsg = 'setImmediate - nested'; - throw new Error(currentMsg); - }); - expectCaught++; - currentMsg = 'process.nextTick - nested'; - throw new Error(currentMsg); - }); - expectCaught++; - setTimeout(function() { - currentMsg = 'setTimeout2 - nested'; - throw new Error(currentMsg); - }); - expectCaught++; - currentMsg = 'setTimeout - nested'; - throw new Error(currentMsg); - }); - expectCaught++; - - removeListener(listener); -}); - - -// FS -errorMsgs.push('fs - file does not exist'); -errorMsgs.push('fs - exists'); -errorMsgs.push('fs - realpath'); -process.nextTick(function() { - addListener(listener); - - fs.stat('does not exist', function(err, stats) { - currentMsg = 'fs - file does not exist'; - throw new Error(currentMsg); - }); - expectCaught++; - - fs.exists('hi all', function(exists) { - currentMsg = 'fs - exists'; - throw new Error(currentMsg); - }); - expectCaught++; - - fs.realpath('/some/path', function(err, resolved) { - currentMsg = 'fs - realpath'; - throw new Error(currentMsg); - }); - expectCaught++; - - removeListener(listener); -}); - - -// Nested FS -errorMsgs.push('fs - nested file does not exist'); -process.nextTick(function() { - addListener(listener); - - setTimeout(function() { - setImmediate(function() { - var b = setInterval(function() { - clearInterval(b); - process.nextTick(function() { - fs.stat('does not exist', function(err, stats) { - currentMsg = 'fs - nested file does not exist'; - throw new Error(currentMsg); - }); - expectCaught++; - }); - }); - }); - }); - - removeListener(listener); -}); - - -// Net -errorMsgs.push('net - connection listener'); -errorMsgs.push('net - client connect'); -errorMsgs.push('net - server listening'); -process.nextTick(function() { - addListener(listener); - - var server = net.createServer(function(c) { - server.close(); - currentMsg = 'net - connection listener'; - throw new Error(currentMsg); - }); - expectCaught++; - - server.listen(common.PORT, function() { - var client = net.connect(common.PORT, function() { - client.end(); - currentMsg = 'net - client connect'; - throw new Error(currentMsg); - }); - expectCaught++; - currentMsg = 'net - server listening'; - throw new Error(currentMsg); - }); - expectCaught++; - - removeListener(listener); -}); - - -// DNS -errorMsgs.push('dns - lookup'); -process.nextTick(function() { - addListener(listener); - - dns.lookup('localhost', function() { - currentMsg = 'dns - lookup'; - throw new Error(currentMsg); - }); - expectCaught++; - - removeListener(listener); -}); diff --git a/test/simple/test-asynclistener-multi-timeout.js b/test/simple/test-asynclistener-multi-timeout.js deleted file mode 100644 index 9af48205450f..000000000000 --- a/test/simple/test-asynclistener-multi-timeout.js +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var tracing = require('tracing'); - -var addListener = tracing.addAsyncListener; -var removeListener = tracing.removeAsyncListener; -var caught = []; -var expect = []; - -var callbacksObj = { - error: function(value, er) { - process._rawDebug('caught', er.message); - caught.push(er.message); - return (expect.indexOf(er.message) !== -1); - } -}; - -var listener = tracing.createAsyncListener(callbacksObj); - -process.on('exit', function(code) { - removeListener(listener); - - if (code > 0) - return; - - expect = expect.sort(); - caught = caught.sort(); - - process._rawDebug('expect', expect); - process._rawDebug('caught', caught); - assert.deepEqual(caught, expect, 'caught all expected errors'); - process._rawDebug('ok'); -}); - - -expect.push('immediate simple a'); -expect.push('immediate simple b'); -process.nextTick(function() { - addListener(listener); - // Tests for a setImmediate specific bug encountered while implementing - // AsyncListeners. - setImmediate(function() { - throw new Error('immediate simple a'); - }); - setImmediate(function() { - throw new Error('immediate simple b'); - }); - removeListener(listener); -}); diff --git a/test/simple/test-asynclistener-remove-add-in-before.js b/test/simple/test-asynclistener-remove-add-in-before.js deleted file mode 100644 index af0bc78e0e83..000000000000 --- a/test/simple/test-asynclistener-remove-add-in-before.js +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var tracing = require('tracing'); -var val; -var callbacks = { - create: function() { - return 42; - }, - before: function() { - tracing.removeAsyncListener(listener); - tracing.addAsyncListener(listener); - }, - after: function(context, storage) { - val = storage; - } -}; - -var listener = tracing.addAsyncListener(callbacks); - -process.nextTick(function() {}); - -process.on('exit', function(status) { - tracing.removeAsyncListener(listener); - assert.equal(status, 0); - assert.equal(val, 42); -}); diff --git a/test/simple/test-asynclistener-remove-before.js b/test/simple/test-asynclistener-remove-before.js deleted file mode 100644 index bc306dbc3c87..000000000000 --- a/test/simple/test-asynclistener-remove-before.js +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var tracing = require('tracing'); -var set = 0; - -var asyncNoHandleError = { - before: function() { - set++; - }, - after: function() { - set++; - } -} - -var key = tracing.addAsyncListener(asyncNoHandleError); - -tracing.removeAsyncListener(key); - -process.nextTick(function() { }); - -process.on('exit', function(code) { - // If the exit code isn't ok then return early to throw the stack that - // caused the bad return code. - if (code !== 0) - return; - - // The async handler should never be called. - assert.equal(set, 0); - console.log('ok'); -}); - - diff --git a/test/simple/test-asynclistener-remove-in-before.js b/test/simple/test-asynclistener-remove-in-before.js deleted file mode 100644 index 06f470ce075f..000000000000 --- a/test/simple/test-asynclistener-remove-in-before.js +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var tracing = require('tracing'); -var done = false; -var callbacks = { - before: function() { - tracing.removeAsyncListener(listener); - }, - after: function() { - done = true; - } -}; - -var listener = tracing.addAsyncListener(callbacks); - -process.nextTick(function() {}); - -process.on('exit', function(status) { - tracing.removeAsyncListener(listener); - assert.equal(status, 0); - assert.ok(done); -}); diff --git a/test/simple/test-asynclistener-remove-inflight-error.js b/test/simple/test-asynclistener-remove-inflight-error.js deleted file mode 100644 index 1b9150152a70..000000000000 --- a/test/simple/test-asynclistener-remove-inflight-error.js +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var tracing = require('tracing'); - -var set = 0; -var asyncNoHandleError = { - error: function() { - set++; - } -} - -var key = tracing.addAsyncListener(asyncNoHandleError); - -process.nextTick(function() { - throw 1; -}); - -tracing.removeAsyncListener(key); - -var uncaughtFired = false; -process.on('uncaughtException', function() { - uncaughtFired = true; - - // Throwing should call the error handler once, then propagate to - // uncaughtException - assert.equal(set, 1); -}); - -process.on('exit', function(code) { - // If the exit code isn't ok then return early to throw the stack that - // caused the bad return code. - if (code !== 0) - return; - - assert.ok(uncaughtFired); - console.log('ok'); -}); diff --git a/test/simple/test-asynclistener-remove-inflight.js b/test/simple/test-asynclistener-remove-inflight.js deleted file mode 100644 index a21b1923f408..000000000000 --- a/test/simple/test-asynclistener-remove-inflight.js +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var tracing = require('tracing'); - -var set = 0; -var asyncNoHandleError = { - before: function() { - set++; - }, - after: function() { - set++; - } -} - -var key = tracing.addAsyncListener(asyncNoHandleError); - -process.nextTick(function() { }); - -tracing.removeAsyncListener(key); - -process.on('exit', function(code) { - // If the exit code isn't ok then return early to throw the stack that - // caused the bad return code. - if (code !== 0) - return; - - // Calling removeAsyncListener *after* a callback is scheduled - // should not affect the handler from responding to the callback. - assert.equal(set, 2); - console.log('ok'); -}); - diff --git a/test/simple/test-asynclistener-run-error-once.js b/test/simple/test-asynclistener-run-error-once.js deleted file mode 100644 index 154decb99af9..000000000000 --- a/test/simple/test-asynclistener-run-error-once.js +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var net = require('net'); -var tracing = require('tracing'); - -var errMsg = 'net - error: server connection'; -var cntr = 0; -var al = tracing.addAsyncListener({ - error: function(stor, er) { - cntr++; - process._rawDebug('Handling error: ' + er.message); - assert.equal(errMsg, er.message); - return true; - } -}); - -process.on('exit', function(status) { - tracing.removeAsyncListener(al); - - console.log('exit status:', status); - assert.equal(status, 0); - console.log('cntr:', cntr); - assert.equal(cntr, 1); - console.log('ok'); -}); - - -var server = net.createServer(function(c) { - this.close(); - throw new Error(errMsg); -}); - - -server.listen(common.PORT, function() { - net.connect(common.PORT, function() { - this.destroy(); - }); -}); diff --git a/test/simple/test-asynclistener-run-inst-once.js b/test/simple/test-asynclistener-run-inst-once.js deleted file mode 100644 index b1492528eede..000000000000 --- a/test/simple/test-asynclistener-run-inst-once.js +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var tracing = require('tracing'); - -var cntr = 0; -var al = tracing.createAsyncListener({ - create: function() { cntr++; }, -}); - -process.on('exit', function() { - assert.equal(cntr, 4); - console.log('ok'); -}); - -tracing.addAsyncListener(al); - -process.nextTick(function() { - tracing.addAsyncListener(al); - process.nextTick(function() { - tracing.addAsyncListener(al); - process.nextTick(function() { - process.nextTick(function() { }); - }); - }); -}); diff --git a/test/simple/test-asynclistener-throw-before-infinite-recursion.js b/test/simple/test-asynclistener-throw-before-infinite-recursion.js deleted file mode 100644 index fdbb50be17d5..000000000000 --- a/test/simple/test-asynclistener-throw-before-infinite-recursion.js +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var tracing = require('tracing'); - -// If there is an uncaughtException listener then the error thrown from -// "before" will be considered handled, thus calling setImmediate to -// finish execution of the nextTickQueue. This in turn will cause "before" -// to fire again, entering into an infinite loop. -// So the asyncQueue is cleared from the returned setImmediate in -// _fatalException to prevent this from happening. -var cntr = 0; - - -tracing.addAsyncListener({ - before: function() { - if (++cntr > 1) { - // Can't throw since uncaughtException will also catch that. - process._rawDebug('Error: Multiple before callbacks called'); - process.exit(1); - } - throw new Error('before'); - } -}); - -process.on('uncaughtException', function() { }); - -process.nextTick(); diff --git a/test/simple/test-asynclistener.js b/test/simple/test-asynclistener.js deleted file mode 100644 index 4c29ec9054f8..000000000000 --- a/test/simple/test-asynclistener.js +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var net = require('net'); -var fs = require('fs'); -var dgram = require('dgram'); -var tracing = require('tracing'); - -var addListener = tracing.addAsyncListener; -var removeListener = tracing.removeAsyncListener; -var actualAsync = 0; -var expectAsync = 0; - -var callbacks = { - create: function onAsync() { - actualAsync++; - } -}; - -var listener = tracing.createAsyncListener(callbacks); - -process.on('exit', function() { - process._rawDebug('expected', expectAsync); - process._rawDebug('actual ', actualAsync); - // TODO(trevnorris): Not a great test. If one was missed, but others - // overflowed then the test would still pass. - assert.ok(actualAsync >= expectAsync); -}); - - -// Test listeners side-by-side -process.nextTick(function() { - addListener(listener); - - var b = setInterval(function() { - clearInterval(b); - }); - expectAsync++; - - var c = setInterval(function() { - clearInterval(c); - }); - expectAsync++; - - setTimeout(function() { }); - expectAsync++; - - setTimeout(function() { }); - expectAsync++; - - process.nextTick(function() { }); - expectAsync++; - - process.nextTick(function() { }); - expectAsync++; - - setImmediate(function() { }); - expectAsync++; - - setImmediate(function() { }); - expectAsync++; - - setTimeout(function() { }, 10); - expectAsync++; - - setTimeout(function() { }, 10); - expectAsync++; - - removeListener(listener); -}); - - -// Async listeners should propagate with nested callbacks -process.nextTick(function() { - addListener(listener); - var interval = 3; - - process.nextTick(function() { - setTimeout(function() { - setImmediate(function() { - var i = setInterval(function() { - if (--interval <= 0) - clearInterval(i); - }); - expectAsync++; - }); - expectAsync++; - process.nextTick(function() { - setImmediate(function() { - setTimeout(function() { }, 20); - expectAsync++; - }); - expectAsync++; - }); - expectAsync++; - }); - expectAsync++; - }); - expectAsync++; - - removeListener(listener); -}); - - -// Test triggers with two async listeners -process.nextTick(function() { - addListener(listener); - addListener(listener); - - setTimeout(function() { - process.nextTick(function() { }); - expectAsync += 2; - }); - expectAsync += 2; - - removeListener(listener); - removeListener(listener); -}); - - -// Test callbacks from fs I/O -process.nextTick(function() { - addListener(listener); - - fs.stat('something random', function(err, stat) { }); - expectAsync++; - - setImmediate(function() { - fs.stat('random again', function(err, stat) { }); - expectAsync++; - }); - expectAsync++; - - removeListener(listener); -}); - - -// Test net I/O -process.nextTick(function() { - addListener(listener); - - var server = net.createServer(function(c) { }); - expectAsync++; - - server.listen(common.PORT, function() { - server.close(); - expectAsync++; - }); - expectAsync++; - - removeListener(listener); -}); - - -// Test UDP -process.nextTick(function() { - addListener(listener); - - var server = dgram.createSocket('udp4'); - expectAsync++; - - server.bind(common.PORT); - - server.close(); - expectAsync++; - - removeListener(listener); -}); diff --git a/test/simple/test-tcp-wrap-connect.js b/test/simple/test-tcp-wrap-connect.js index 43fb37ac7011..9e915d243bae 100644 --- a/test/simple/test-tcp-wrap-connect.js +++ b/test/simple/test-tcp-wrap-connect.js @@ -22,11 +22,13 @@ var common = require('../common'); var assert = require('assert'); var TCP = process.binding('tcp_wrap').TCP; +var TCPConnectWrap = process.binding('tcp_wrap').TCPConnectWrap; +var ShutdownWrap = process.binding('stream_wrap').ShutdownWrap; function makeConnection() { var client = new TCP(); - var req = {}; + var req = new TCPConnectWrap(); var err = client.connect(req, '127.0.0.1', common.PORT); assert.equal(err, 0); @@ -36,7 +38,7 @@ function makeConnection() { assert.equal(req, req_); console.log('connected'); - var shutdownReq = {}; + var shutdownReq = new ShutdownWrap(); var err = client.shutdown(shutdownReq); assert.equal(err, 0); diff --git a/test/simple/test-tcp-wrap-listen.js b/test/simple/test-tcp-wrap-listen.js index fb3175a008a1..5801368ba1e8 100644 --- a/test/simple/test-tcp-wrap-listen.js +++ b/test/simple/test-tcp-wrap-listen.js @@ -23,6 +23,7 @@ var common = require('../common'); var assert = require('assert'); var TCP = process.binding('tcp_wrap').TCP; +var WriteWrap = process.binding('stream_wrap').WriteWrap; var server = new TCP(); @@ -55,7 +56,8 @@ server.onconnection = function(err, client) { assert.equal(0, client.writeQueueSize); - var req = { async: false }; + var req = new WriteWrap(); + req.async = false; var err = client.writeBuffer(req, buffer); assert.equal(err, 0); client.pendingWrites.push(req); diff --git a/test/simple/test-v8-gc.js b/test/simple/test-v8-gc.js deleted file mode 100644 index 077e48c574e7..000000000000 --- a/test/simple/test-v8-gc.js +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// Flags: --expose_gc - -var common = require('../common'); -var assert = require('assert'); -var v8 = require('tracing').v8; - -assert(typeof gc === 'function', 'Run this test with --expose_gc.'); - -var ncalls = 0; -var before; -var after; - -function ongc(before_, after_) { - // Try very hard to not create garbage because that could kick off another - // garbage collection cycle. - before = before_; - after = after_; - ncalls += 1; -} - -gc(); -v8.on('gc', ongc); -gc(); -v8.removeListener('gc', ongc); -gc(); - -assert.equal(ncalls, 1); -assert.equal(typeof before, 'object'); -assert.equal(typeof after, 'object'); -assert.equal(typeof before.timestamp, 'number'); -assert.equal(typeof after.timestamp, 'number'); -assert.equal(before.timestamp <= after.timestamp, true); diff --git a/test/simple/test-v8-stats.js b/test/simple/test-v8-stats.js deleted file mode 100644 index 6d70fb9a02a5..000000000000 --- a/test/simple/test-v8-stats.js +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var v8 = require('tracing').v8; - -var s = v8.getHeapStatistics(); -var keys = [ - 'heap_size_limit', - 'total_heap_size', - 'total_heap_size_executable', - 'total_physical_size', - 'used_heap_size']; -assert.deepEqual(Object.keys(s).sort(), keys); -keys.forEach(function(key) { - assert.equal(typeof s[key], 'number'); -});