From 173a8c984217dcf2ba32caa389f6abaca732382d Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Wed, 3 Feb 2010 10:05:24 -0800 Subject: [PATCH 1/9] Disable dns and fs-sendfile tests. --- test/mjsunit/{ => disabled}/test-dns.js | 0 test/mjsunit/{ => disabled}/test-fs-sendfile.js | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename test/mjsunit/{ => disabled}/test-dns.js (100%) rename test/mjsunit/{ => disabled}/test-fs-sendfile.js (100%) diff --git a/test/mjsunit/test-dns.js b/test/mjsunit/disabled/test-dns.js similarity index 100% rename from test/mjsunit/test-dns.js rename to test/mjsunit/disabled/test-dns.js diff --git a/test/mjsunit/test-fs-sendfile.js b/test/mjsunit/disabled/test-fs-sendfile.js similarity index 100% rename from test/mjsunit/test-fs-sendfile.js rename to test/mjsunit/disabled/test-fs-sendfile.js From 8f52142116a134b95407d6f9f11d022bc6d9cf8f Mon Sep 17 00:00:00 2001 From: Aaron Heckmann Date: Sat, 30 Jan 2010 23:41:22 -0500 Subject: [PATCH 2/9] look for -1 instead of false returned from string.indexOf --- lib/multipart.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/multipart.js b/lib/multipart.js index 826be951ee..dc2a8cea88 100644 --- a/lib/multipart.js +++ b/lib/multipart.js @@ -183,7 +183,7 @@ Part.prototype.write = function(chunk) { var header = this.buffer.substr(0, offset).split(/: ?/); this.headers[header[0].toLowerCase()] = header[1]; this.buffer = this.buffer.substr(offset+2); - } else if (offset === false) { + } else if (offset === -1) { return; } } From f3ad63557611b7f6a1bafd412a97c5c6de127162 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Wed, 3 Feb 2010 12:19:08 -0800 Subject: [PATCH 3/9] Downcase process.ARGV/ENV to process.argv/env --- doc/api.txt | 8 ++++---- src/node.cc | 7 +++++-- src/node.js | 24 ++++++++++++------------ 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/doc/api.txt b/doc/api.txt index 27cc1f14b6..c746e07075 100644 --- a/doc/api.txt +++ b/doc/api.txt @@ -48,7 +48,7 @@ execution. === Global Objects -+GLOBAL+ :: ++global+ :: The global namespace object. +process+ :: @@ -100,10 +100,10 @@ more information. signal names such as SIGINT, SIGUSR1, etc. |========================================================= -+process.ARGV+ :: ++process.argv+ :: An array containing the command line arguments. -+process.ENV+ :: ++process.env+ :: An object containing the user environment. See environ(7). +process.pid+ :: @@ -565,7 +565,7 @@ Node provides a tridirectional +popen(3)+ facility through the class +"error"+ callbacks will no longer be made. |========================================================= -+process.createChildProcess(command, args=[], env=ENV)+:: ++process.createChildProcess(command, args=[], env=process.env)+:: Launches a new process with the given +command+, command line arguments, and environmental variables. For example: + diff --git a/src/node.cc b/src/node.cc index 00d1c8ceef..c7dac8e2e8 100644 --- a/src/node.cc +++ b/src/node.cc @@ -914,7 +914,7 @@ static void Load(int argc, char *argv[]) { #define str(s) #s process->Set(String::NewSymbol("platform"), String::New(xstr(PLATFORM))); - // process.ARGV + // process.argv int i, j; Local arguments = Array::New(argc - dash_dash_index + 1); arguments->Set(Integer::New(0), String::New(argv[0])); @@ -924,8 +924,9 @@ static void Load(int argc, char *argv[]) { } // assign it process->Set(String::NewSymbol("ARGV"), arguments); + process->Set(String::NewSymbol("argv"), arguments); - // create process.ENV + // create process.env Local env = Object::New(); for (i = 0; environ[i]; i++) { // skip entries without a '=' character @@ -941,6 +942,8 @@ static void Load(int argc, char *argv[]) { } // assign process.ENV process->Set(String::NewSymbol("ENV"), env); + process->Set(String::NewSymbol("env"), env); + process->Set(String::NewSymbol("pid"), Integer::New(getpid())); // define various internal methods diff --git a/src/node.js b/src/node.js index 0f890ff0f8..dcd0d1b884 100644 --- a/src/node.js +++ b/src/node.js @@ -86,7 +86,7 @@ process.inherits = function (ctor, superCtor) { process.createChildProcess = function (file, args, env) { var child = new process.ChildProcess(); args = args || []; - env = env || process.ENV; + env = env || process.env; var envPairs = []; for (var key in env) { if (env.hasOwnProperty(key)) { @@ -493,7 +493,7 @@ GLOBAL.clearInterval = GLOBAL.clearTimeout; // Modules var debugLevel = 0; -if ("NODE_DEBUG" in process.ENV) debugLevel = 1; +if ("NODE_DEBUG" in process.env) debugLevel = 1; function debug (x) { if (debugLevel > 0) { @@ -744,12 +744,12 @@ var path = pathModule.exports; process.paths = [ path.join(process.installPrefix, "lib/node/libraries") ]; -if (process.ENV["HOME"]) { - process.paths.unshift(path.join(process.ENV["HOME"], ".node_libraries")); +if (process.env["HOME"]) { + process.paths.unshift(path.join(process.env["HOME"], ".node_libraries")); } -if (process.ENV["NODE_PATH"]) { - process.paths = process.ENV["NODE_PATH"].split(":").concat(process.paths); +if (process.env["NODE_PATH"]) { + process.paths = process.env["NODE_PATH"].split(":").concat(process.paths); } @@ -968,19 +968,19 @@ process.exit = function (code) { var cwd = process.cwd(); -// Make process.ARGV[0] and process.ARGV[1] into full paths. -if (process.ARGV[0].indexOf('/') > 0) { - process.ARGV[0] = path.join(cwd, process.ARGV[0]); +// Make process.argv[0] and process.argv[1] into full paths. +if (process.argv[0].indexOf('/') > 0) { + process.argv[0] = path.join(cwd, process.argv[0]); } -if (process.ARGV[1].charAt(0) != "/" && !(/^http:\/\//).exec(process.ARGV[1])) { - process.ARGV[1] = path.join(cwd, process.ARGV[1]); +if (process.argv[1].charAt(0) != "/" && !(/^http:\/\//).exec(process.argv[1])) { + process.argv[1] = path.join(cwd, process.argv[1]); } // Load the main module--the command line argument. process.mainModule = createModule("."); var loadPromise = new events.Promise(); -process.mainModule.load(process.ARGV[1], loadPromise); +process.mainModule.load(process.argv[1], loadPromise); // All our arguments are loaded. We've evaluated all of the scripts. We // might even have created TCP servers. Now we enter the main eventloop. If From 0cfa789cc530848725a8cb5595224e78ae7b9dd0 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Wed, 3 Feb 2010 12:14:51 -0800 Subject: [PATCH 4/9] bump version --- ChangeLog | 36 +++++++++++++++++++++++++++++++++++- doc/api.txt | 2 +- doc/index.html | 4 ++-- wscript | 2 +- 4 files changed, 39 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index a0ca933870..46318dd4dc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,38 @@ -2010.01.20, Version 0.1.26 +2010.02.03, Version 0.1.27 + + * Implemented __dirname (Felix Geisendörfer) + + * Downcase process.ARGV, process.ENV, GLOBAL + (now process.argv, process.env, global) + + * Bug Fix: Late promise promise callbacks firing + (Felix Geisendörfer, Jonas Pfenniger) + + * Make assert.AssertionError instance of Error + + * Removed inline require call for querystring + (self@cloudhead.net) + + * Add support for MX, TXT, and SRV records in DNS module. + (Blaine Cook) + + * Bugfix: HTTP client automatically reconnecting + + * Adding OS X .dmg build scripts. (Standa Opichal) + + * Bugfix: ObjectWrap memory leak + + * Bugfix: Multipart handle Content-Type headers with charset + (Felix Geisendörfer) + + * Upgrade http-parser to fix header overflow attack. + + * Upgrade V8 to 2.1.0 + + * Various other bug fixes, performance improvements. + + +2010.01.20, Version 0.1.26, da00413196e432247346d9e587f8c78ce5ceb087 * Bugfix, HTTP eof causing crash (Ben Williamson) diff --git a/doc/api.txt b/doc/api.txt index c746e07075..55f68a824d 100644 --- a/doc/api.txt +++ b/doc/api.txt @@ -1,7 +1,7 @@ NODE(1) ======= Ryan Dahl -Version, 0.1.26, 2010.01.20 +Version, 0.1.27, 2010.02.03 == NAME diff --git a/doc/index.html b/doc/index.html index fe8800a18b..de7efdd7e5 100644 --- a/doc/index.html +++ b/doc/index.html @@ -97,9 +97,9 @@ server.listen(7000, "localhost"); git repo

- 2010.01.20 + 2010.02.03 node-v0.1.26.tar.gz + href="http://s3.amazonaws.com/four.livejournal/20100203/node-v0.1.27.tar.gz">node-v0.1.27.tar.gz

Build

diff --git a/wscript b/wscript index 8e2a79cf4a..92a6c199b9 100644 --- a/wscript +++ b/wscript @@ -7,7 +7,7 @@ from os.path import join, dirname, abspath from logging import fatal cwd = os.getcwd() -VERSION="0.1.26" +VERSION="0.1.27" APPNAME="node.js" import js2c From e5a41a75b7b2f6bf423ead71823e7a7a024ec786 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Wed, 3 Feb 2010 12:57:05 -0800 Subject: [PATCH 5/9] Revert "Adding output of Platform information into the test runner" Broken on at least one platform http://pastie.org/808217 This reverts commit 704f394c6671af5b981900fc3666f1b97ef580a9. --- tools/test.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/test.py b/tools/test.py index 607a62e614..74bde14abf 100755 --- a/tools/test.py +++ b/tools/test.py @@ -101,7 +101,6 @@ class ProgressIndicator(object): # ...and then reraise the exception to bail out raise self.Done() - print "\r\nPlatform: {0} {1}".format(platform.system(), platform.release()) return not self.failed def RunSingle(self): From b73f61a137841cebac8459203b6be3baa1756980 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Geisend=C3=B6rfer?= Date: Thu, 4 Feb 2010 22:28:04 +0100 Subject: [PATCH 6/9] Simplified module system createModule got removed as it was unnecessary and caused issues by doing its own cache checks independent of loadModule. Internal modules are now the only globally cached modules, all other modules are only cached by inheriting their parent modules cache. Credits: Module specific cache and a few other diffs by Blaine Cook http://github.com/blaine/node/commit/431662d25c0db3096deb5f679ca73b1dd6bb8ae5 http://romeda.org/blog/2010/01/hot-code-loading-in-nodejs.html http://thread.gmane.org/gmane.comp.lang.javascript.nodejs/1994 --- src/node.js | 59 ++++++++++++++++------------- test/mjsunit/test-module-loading.js | 1 - 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/src/node.js b/src/node.js index dcd0d1b884..76ac289860 100644 --- a/src/node.js +++ b/src/node.js @@ -41,11 +41,20 @@ node.dns.createConnection = removed("node.dns.createConnection() has moved. Use // Module +var internalModuleCache = {}; + function Module (id, parent) { this.id = id; this.exports = {}; this.parent = parent; + this.moduleCache = {}; + + if (parent) { + process.mixin(this.moduleCache, parent.moduleCache); + this.moduleCache[parent.id] = parent; + } + this.filename = null; this.loaded = false; this.loadPromise = null; @@ -53,23 +62,11 @@ function Module (id, parent) { this.children = []; }; -var moduleCache = {}; - -function createModule (id, parent) { - if (id in moduleCache) { - debug("found " + JSON.stringify(id) + " in cache"); - return moduleCache[id]; - } - debug("didn't found " + JSON.stringify(id) + " in cache. creating new module"); - var m = new Module(id, parent); - moduleCache[id] = m; - return m; -}; - function createInternalModule (id, constructor) { - var m = createModule(id); + var m = new Module(id); constructor(m.exports); m.loaded = true; + internalModuleCache[id] = m; return m; }; @@ -803,11 +800,7 @@ function findModulePath (id, dirs, callback) { searchLocations(); } -function loadModule (request, parent) { - // This is the promise which is actually returned from require.async() - var loadPromise = new events.Promise(); - - // debug("loadModule REQUEST " + (request) + " parent: " + JSON.stringify(parent)); +function resolveModulePath(request, parent) { var id, paths; if (request.charAt(0) == "." && (request.charAt(1) == "/" || request.charAt(1) == ".")) { @@ -823,21 +816,33 @@ function loadModule (request, parent) { paths = process.paths; } - if (id in moduleCache) { + return [id, paths]; +} + +function loadModule (request, parent) { + var + // The promise returned from require.async() + loadPromise = new events.Promise(), + resolvedModule = resolveModulePath(request, parent), + id = resolvedModule[0], + paths = resolvedModule[1]; + + // debug("loadModule REQUEST " + (request) + " parent: " + JSON.stringify(parent)); + + var cachedModule = internalModuleCache[id] || parent.moduleCache[id]; + if (cachedModule) { debug("found " + JSON.stringify(id) + " in cache"); - // In cache - var module = moduleCache[id]; - process.nextTick(function () { - loadPromise.emitSuccess(module.exports); + process.nextTick(function() { + loadPromise.emitSuccess(cachedModule.exports); }); - } else { + } else { debug("looking for " + JSON.stringify(id) + " in " + JSON.stringify(paths)); // Not in cache findModulePath(request, paths, function (filename) { if (!filename) { loadPromise.emitError(new Error("Cannot find module '" + request + "'")); } else { - var module = createModule(id, parent); + var module = new Module(id, parent); module.load(filename, loadPromise); } }); @@ -978,7 +983,7 @@ if (process.argv[1].charAt(0) != "/" && !(/^http:\/\//).exec(process.argv[1])) { } // Load the main module--the command line argument. -process.mainModule = createModule("."); +process.mainModule = new Module("."); var loadPromise = new events.Promise(); process.mainModule.load(process.argv[1], loadPromise); diff --git a/test/mjsunit/test-module-loading.js b/test/mjsunit/test-module-loading.js index 2ff9c41b41..416c48b140 100644 --- a/test/mjsunit/test-module-loading.js +++ b/test/mjsunit/test-module-loading.js @@ -41,7 +41,6 @@ assert.notEqual(one.hello, two.hello); debug("test cycles containing a .. path"); var root = require("./fixtures/cycles/root"), foo = require("./fixtures/cycles/folder/foo"); -assert.equal(root.foo, foo); assert.equal(root.sayHello(), root.hello); var errorThrown = false; From c05b5d8b59b4f18926825f091b4d364f439cecb2 Mon Sep 17 00:00:00 2001 From: Mikeal Rogers Date: Thu, 7 Jan 2010 00:41:59 -0800 Subject: [PATCH 7/9] Adding test for bug in stdio. http://groups.google.com/group/nodejs/browse_thread/thread/10fda8eaf7276642/e5d5147f2b666abd --- test/mjsunit/fixtures/echo.js | 5 +++++ test/mjsunit/test-readdir.js | 15 ++++++++++++--- test/mjsunit/test-stdio.js | 21 +++++++++++++++++++++ 3 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 test/mjsunit/fixtures/echo.js create mode 100644 test/mjsunit/test-stdio.js diff --git a/test/mjsunit/fixtures/echo.js b/test/mjsunit/fixtures/echo.js new file mode 100644 index 0000000000..49f435cc7a --- /dev/null +++ b/test/mjsunit/fixtures/echo.js @@ -0,0 +1,5 @@ +process.mixin(require("../common")); +process.stdio.open(); +process.stdio.addListener("data", function (data) { + puts(data); +}); \ No newline at end of file diff --git a/test/mjsunit/test-readdir.js b/test/mjsunit/test-readdir.js index 16c46a2aa2..766dc6ef46 100644 --- a/test/mjsunit/test-readdir.js +++ b/test/mjsunit/test-readdir.js @@ -7,9 +7,18 @@ puts("readdir " + fixturesDir); promise.addCallback(function (files) { p(files); - assert.deepEqual(["a.js", "b","cycles", "multipart.js", - "nested-index","test_ca.pem", - "test_cert.pem", "test_key.pem", "throws_error.js", "x.txt"], files.sort()); + assert.deepEqual(['a.js' + , 'b' + , 'cycles' + , 'echo.js' + , 'multipart.js' + , 'nested-index' + , 'test_ca.pem' + , 'test_cert.pem' + , 'test_key.pem' + , 'throws_error.js' + , 'x.txt' + ], files.sort()); }); promise.addErrback(function () { diff --git a/test/mjsunit/test-stdio.js b/test/mjsunit/test-stdio.js new file mode 100644 index 0000000000..9570539d7d --- /dev/null +++ b/test/mjsunit/test-stdio.js @@ -0,0 +1,21 @@ +process.mixin(require("./common")); + +var sub = path.join(fixturesDir, 'echo.js'); + +var result = false; + +var child = process.createChildProcess(path.join(libDir, "../bin/node"), [sub]); +child.addListener("error", function (data){ + puts("parent stderr: " + data); +}); +child.addListener("output", function (data){ + if (data && data[0] == 't') { + result = true; + } +}); +setTimeout(function () { + child.write('t\r\n'); +}, 100); +setTimeout(function (){ + assert.ok(result); +}, 500) From fe85062046ac36c2207aa0bbd2f496663eaca996 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Fri, 5 Feb 2010 17:14:14 -0800 Subject: [PATCH 8/9] Bugfix: blocked pumping in stdio coupling This should fix the test in c05b5d8 by Mikeal Rogers. --- deps/coupling/coupling.c | 206 ++++++++++++++++++++++++---------- test/mjsunit/fixtures/echo.js | 11 +- test/mjsunit/test-stdio.js | 36 ++++-- 3 files changed, 178 insertions(+), 75 deletions(-) diff --git a/deps/coupling/coupling.c b/deps/coupling/coupling.c index 57eca1c8ce..f6b03f38eb 100644 --- a/deps/coupling/coupling.c +++ b/deps/coupling/coupling.c @@ -143,98 +143,176 @@ ring_buffer_push (ring_buffer *ring, int fd) return r; } +/* PULL PUMP + * + * This is used to read data from a blocking file descriptor and pump it into + * a non-blocking pipe (or other non-blocking fd). The algorithm is this: + * + * while (true) { + * read(STDIN_FILENO) // blocking + * + * while (!ring.empty) { + * write(pipe) // non-blocking + * select(pipe, writable) + * } + * } + * + */ static void -pump (int is_pull, int pullfd, int pushfd) +pull_pump (int pullfd, int pushfd) { int r; ring_buffer ring; - fd_set readfds, writefds, exceptfds; + + fd_set writefds, exceptfds; + FD_ZERO(&exceptfds); + FD_ZERO(&writefds); + FD_SET(pushfd, &exceptfds); + FD_SET(pushfd, &writefds); ring_buffer_init(&ring); - int maxfd; + while (pullfd >= 0) { + /* Blocking read from STDIN_FILENO */ + r = ring_buffer_pull(&ring, pullfd); - while (pushfd >= 0 && (pullfd >= 0 || !ring_buffer_empty_p(&ring))) { - FD_ZERO(&exceptfds); - FD_ZERO(&readfds); - FD_ZERO(&writefds); - - maxfd = -1; - - if (is_pull) { - if (!ring_buffer_empty_p(&ring)) { - maxfd = pushfd; - FD_SET(pushfd, &exceptfds); - FD_SET(pushfd, &writefds); - } - } else { - if (pullfd >= 0) { - if (!ring_buffer_filled_p(&ring)) { - maxfd = pullfd; - FD_SET(pullfd, &exceptfds); - FD_SET(pullfd, &readfds); + if (r == 0) { + /* eof */ + close(pullfd); + pullfd = -1; + } else if (r < 0 && errno != EINTR && errno != EAGAIN) { + /* error */ + perror("pull_pump read()"); + close(pullfd); + pullfd = -1; + } + + /* Push all of the data in the ring buffer out. */ + while (!ring_buffer_empty_p(&ring)) { + /* non-blocking write() to the pipe */ + r = ring_buffer_push(&ring, pushfd); + + if (r < 0 && errno != EAGAIN && errno != EINTR) { + if (errno == EPIPE) { + /* This happens if someone closes the other end of the pipe. This + * is a normal forced close of STDIN. Hopefully there wasn't data + * in the ring buffer. Just close both ends and exit. + */ + close(pushfd); + close(pullfd); + pushfd = pullfd = -1; + } else { + perror("pull_pump write()"); + close(pushfd); + close(pullfd); } + return; } - } - if (maxfd >= 0) { - r = select(maxfd+1, &readfds, &writefds, &exceptfds, NULL); + /* Select for writablity on the pipe end. + * Very rarely will this stick. + */ + r = select(pushfd+1, NULL, &writefds, &exceptfds, NULL); - if (r < 0 || (pullfd >= 0 && FD_ISSET(pushfd, &exceptfds))) { + if (r < 0 || FD_ISSET(pushfd, &exceptfds)) { close(pushfd); close(pullfd); pushfd = pullfd = -1; return; } } + } + assert(pullfd < 0); + assert(ring_buffer_empty_p(&ring)); + close(pushfd); +} + +/* PUSH PUMP + * + * This is used to push data out to a blocking file descriptor. It pulls + * data from a non-blocking pipe (pullfd) and pushes to STDOUT_FILENO + * (pushfd). + * When the pipe is closed, then the rest of the data is pushed out and then + * STDOUT_FILENO is closed. + * + * The algorithm looks roughly like this: + * + * while (true) { + * r = read(pipe) // nonblocking + * + * while (!ring.empty) { + * write(STDOUT_FILENO) // blocking + * } + * + * select(pipe, readable); + * } + */ +static void +push_pump (int pullfd, int pushfd) +{ + int r; + ring_buffer ring; + + fd_set readfds, exceptfds; + FD_ZERO(&exceptfds); + FD_ZERO(&readfds); + FD_SET(pullfd, &exceptfds); + FD_SET(pullfd, &readfds); + + ring_buffer_init(&ring); + + /* The pipe is open or there is data left to be pushed out + * NOTE: if pushfd (STDOUT_FILENO) ever errors out, then we just exit the + * loop. + */ + while (pullfd >= 0 || !ring_buffer_empty_p(&ring)) { - if (pullfd >= 0 && FD_ISSET(pullfd, &exceptfds)) { + /* Pull from the non-blocking pipe */ + r = ring_buffer_pull(&ring, pullfd); + + if (r == 0) { + /* eof */ + close(pullfd); + pullfd = -1; + } else if (r < 0 && errno != EINTR && errno != EAGAIN) { + perror("push_pump read()"); close(pullfd); pullfd = -1; + return; } - if (pullfd >= 0 && (is_pull || FD_ISSET(pullfd, &readfds))) { - r = ring_buffer_pull(&ring, pullfd); - if (r == 0) { - /* eof */ - close(pullfd); - pullfd = -1; + /* Push everything out to STDOUT */ + while (!ring_buffer_empty_p(&ring)) { + /* Blocking write() to pushfd (STDOUT_FILENO) */ + r = ring_buffer_push(&ring, pushfd); + + /* If there was a problem, just exit the entire function */ - } else if (r < 0) { - if (errno != EINTR && errno != EAGAIN) goto error; + if (r < 0 && errno != EINTR) { + close(pushfd); + close(pullfd); + pushfd = pullfd = -1; + return; } } + + if (pullfd >= 0) { + /* select for readability on the pullfd */ + r = select(pullfd+1, &readfds, NULL, &exceptfds, NULL); - if (!is_pull || FD_ISSET(pushfd, &writefds)) { - r = ring_buffer_push(&ring, pushfd); - if (r < 0) { - switch (errno) { - case EINTR: - case EAGAIN: - continue; - - case EPIPE: - /* TODO catch SIGPIPE? */ - close(pushfd); - close(pullfd); - pushfd = pullfd = -1; - return; - - default: - goto error; - } + if (r < 0 || FD_ISSET(pullfd, &exceptfds)) { + close(pushfd); + close(pullfd); + pushfd = pullfd = -1; + return; } } } - + /* If we got here then we got eof on pullfd and pushed all the data out. + * so now just close pushfd */ + assert(pullfd < 0); + assert(ring_buffer_empty_p(&ring)); close(pushfd); - close(pullfd); - return; - -error: - close(pushfd); - close(pullfd); - perror("(coupling) pump"); } static inline int @@ -262,7 +340,11 @@ pump_thread (void *data) { struct coupling *c = (struct coupling*)data; - pump(c->is_pull, c->pullfd, c->pushfd); + if (c->is_pull) { + pull_pump(c->pullfd, c->pushfd); + } else { + push_pump(c->pullfd, c->pushfd); + } return NULL; } diff --git a/test/mjsunit/fixtures/echo.js b/test/mjsunit/fixtures/echo.js index 49f435cc7a..0aed0ff84c 100644 --- a/test/mjsunit/fixtures/echo.js +++ b/test/mjsunit/fixtures/echo.js @@ -1,5 +1,12 @@ process.mixin(require("../common")); process.stdio.open(); + +print("hello world\r\n"); + process.stdio.addListener("data", function (data) { - puts(data); -}); \ No newline at end of file + print(data); +}); + +process.stdio.addListener("close", function () { + process.stdio.close(); +}); diff --git a/test/mjsunit/test-stdio.js b/test/mjsunit/test-stdio.js index 9570539d7d..e8bc6842d0 100644 --- a/test/mjsunit/test-stdio.js +++ b/test/mjsunit/test-stdio.js @@ -2,20 +2,34 @@ process.mixin(require("./common")); var sub = path.join(fixturesDir, 'echo.js'); -var result = false; - -var child = process.createChildProcess(path.join(libDir, "../bin/node"), [sub]); +var gotHelloWorld = false; +var gotEcho = false; + +var child = process.createChildProcess(process.argv[0], [sub]); + child.addListener("error", function (data){ puts("parent stderr: " + data); }); + child.addListener("output", function (data){ - if (data && data[0] == 't') { - result = true; + if (data) { + puts('child said: ' + JSON.stringify(data)); + if (!gotHelloWorld) { + assert.equal("hello world\r\n", data); + gotHelloWorld = true; + child.write('echo me\r\n'); + } else { + assert.equal("echo me\r\n", data); + gotEcho = true; + child.close(); + } + } else { + puts('child eof'); } }); -setTimeout(function () { - child.write('t\r\n'); -}, 100); -setTimeout(function (){ - assert.ok(result); -}, 500) + + +process.addListener('exit', function () { + assert.ok(gotHelloWorld); + assert.ok(gotEcho); +}); From 1737cdc1120a9e64db58780cb1286490b0b108c0 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Wed, 13 Jan 2010 09:38:27 -0800 Subject: [PATCH 9/9] Fix the documentation of dns error handling. These are actually passed as Error objects, not separate "code" and "message" parameters. --- doc/api.txt | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/doc/api.txt b/doc/api.txt index 55f68a824d..12e61b02a6 100644 --- a/doc/api.txt +++ b/doc/api.txt @@ -1459,14 +1459,14 @@ resolution.addCallback(function (addresses, ttl, cname) { reversing.addCallback( function (domains, ttl, cname) { sys.puts("reverse for " + a + ": " + JSON.stringify(domains)); }); - reversing.addErrback( function (code, msg) { - sys.puts("reverse for " + a + " failed: " + msg); + reversing.addErrback( function (e) { + puts("reverse for " + a + " failed: " + e.message); }); } }); -resolution.addErrback(function (code, msg) { - sys.puts("error: " + msg); +resolution.addErrback(function (e) { + puts("error: " + e.message); }); ------------------------------------------------------------------------- @@ -1482,8 +1482,9 @@ This function returns a promise. canonical name for the query. The type of each item in +addresses+ is determined by the record type, and described in the documentation for the corresponding lookup methods below. -- on error: returns +code, msg+. +code+ is one of the error codes listed - below and +msg+ is a string describing the error in English. +- on error: Returns an instanceof Error object, where the "errno" field is one + of the error codes listed below and the "message" field is a string + describing the error in English. +dns.resolve4(domain)+:: @@ -1521,8 +1522,9 @@ Reverse resolves an ip address to an array of domain names. - on success: returns +domains, ttl, cname+. +ttl+ (time-to-live) is an integer specifying the number of seconds this result is valid for. +cname+ is the canonical name for the query. +domains+ is an array of domains. -- on error: returns +code, msg+. +code+ is one of the error codes listed - below and +msg+ is a string describing the error in English. +- on error: Returns an instanceof Error object, where the "errno" field is one + of the error codes listed below and the "message" field is a string + describing the error in English. Each DNS query can return an error code.