Created
April 3, 2012 17:43
-
-
Save isaacs/2294039 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
In a child process, each of the stdio streams may be set to | |
one of the following: | |
1. A new file descriptor in the child, dup2'ed to the parent and | |
exposed to JS as a Stream object. | |
2. A copy of a file descriptor from the parent, with no other | |
added magical stuff. | |
3. A black hole - no pipe created. | |
The trouble with using raw file descriptor integers for this is | |
that they are not portable to Windows. | |
The 'stdio' option to child_process.spawn() is an array where each | |
index corresponds to a fd in the child. The value is one of the following: | |
1. `null` or `undefined` - Use the default value. For 0,1,2, | |
this is the same as 'pipe'. For any higher value, 'ignore' | |
2. 'ignore' - Open the fd in the child, and /dev/null it | |
3. 'pipe' - Create a new dup2 pipe, and expose a stream object to JS. | |
4. 'ipc' - The same as 'pipe', but set up to send/receive IPC messages and | |
pass server/socket/FD handles for use with cluster. | |
Note: A ChildProcess may have at most *one* IPC stdio file descriptor. | |
Setting this option enables the ChildProcess.send() method. If the | |
child writes JSON messages to this file descriptor, then this will trigger | |
ChildProcess.on('message'). If the child is a Node.js program, then | |
the presence of an IPC channel will enable process.send() and | |
process.on('message') | |
5. positive integer - call tty_wrap.guessHandleType. Create the appropriate | |
pipe_wrap type of thing for this. Note that this will generally not | |
be a portable way to share a socket with the child process as a | |
stdio fd. | |
6. Any HandleWrap object - If the object is a HandleWrap object, | |
then the underlying TCP, Pipe, or File handle is shared with the | |
child process. | |
7. Any {handle:<instanceof HandleWrap>} object - If the object has a | |
`handle` member which is a HandleWrap object of some sort, then | |
treat this as #5. | |
8. Any {fd:<positive integer>} object - If the object has an ingeter `fd` member, | |
then treat this as #4. | |
9. Any negative integer: The same as 'pipe' (Backwards compatibility with | |
customFds.) | |
10. Anything else: throw. | |
As a shorthand, the `stdio` argument may also be one of the following | |
strings, rather than an array: | |
* `ignore` --> ['ignore', 'ignore', 'ignore'] | |
* `pipe` --> ['pipe', 'pipe', 'pipe'] == [-1,-1,-1] | |
* `inherit` --> [process.stdin, process.stdout, process.stderr] == [0,1,2] | |
Defaults: | |
* `spawn`, `exec`, `execFile` --> ['pipe', 'pipe', 'pipe'] | |
* `fork` --> ['ipc', 'pipe', 'pipe'] or ['ipc', 'ignore', 'ignore'] if | |
{ silent: true } | |
Since cluster just uses child_process.fork, it'll use the same defaults. | |
This will require a bit of refactoring in other parts of node besides | |
child_process.js: | |
* TCP and TTY sockets have a "handle" member added and exposed explicitly. | |
* createPipe() should be blessed as a public API so that users can create | |
arbitrary duplex streams for stdio. | |
## createPipe([options]) | |
* `options` {Object} | |
* `ipc` {Boolean} Default=false | |
* `readable` {Boolean} Default=true | |
* `writable` {Boolean} Default=true | |
* return: Pipe stream object | |
By default, all created pipes are duplex. The readable/writable aspect is | |
only set at the JavaScript layer to help prevent doing the wrong sort of | |
stream.pipe(). At the low-level, there is no special half-duplex behavior. | |
IPC is only enabled if explicitly requested, usually by setting 'ipc' as one | |
of the stdio FD options. | |
The return object is a Stream object. It has a "remote" member which | |
is an opaque object representing the other end of the pipe pair, and | |
is actually used by spawn. | |
Example: | |
```javascript | |
var p = createPipe() | |
var c = spawn(cmd, args, { stdio: [ p ] }) | |
p === c.stdin | |
p.on('data', function (chunk) { | |
console.error('c.stdin emitted data', chunk) | |
}) | |
``` | |
## Exposure on the ChildProcess object. | |
The stdin/stdout/stderr members will be set to a Stream object if set to | |
`pipe`, or null otherwise. | |
If an `ipc` channel was requested, then the ChildProcess object will have | |
a `send(msg)` method, and will perhaps `emit('message', obj)` if the child | |
writes JSON to that channel. | |
Other stdio fds will be exposed on the `stdio` member. ChildProcess.stdio | |
is an Array corresponding to the file descriptors opened in the child. | |
child.stdio[0] === child.stdin, child.stdio[2] === child.stderr, etc. | |
*/ | |
// Examples | |
// 1. spawn a child, taking over the parent's terminal. | |
spawn(cmd, args, { stdio: 'inherit' }) | |
// 2. spawn a child, sharing only stderr | |
spawn(cmd, args, { stdio: ['pipe', 'pipe', process.stderr] }) | |
// 3. since integer FDs will be inspected and set up appropriately, | |
// customFds-style will continue to work without modification | |
spawn(cmd, args, { stdio: [-1, -1, 2] }) | |
// 4. Open an extra fd=4, to interact with programs present a | |
// startd-style interface. | |
spawn(cmd, args, { stdio: ['pipe', 'ignore', 'ignore', null, 'pipe'] }) | |
// 5. Provide a socket as the stdin and stdio to a child, | |
// to interact with programs that present a cgi-style interface | |
net.createServer(function (conn) { | |
spawn(cmd, args, { stdio: [ conn, conn, process.stderr ] }) | |
}).listen(80) | |
// 6. Same as #5, but log stderr to a file: | |
fs.open('error.log', function (er, fd) { | |
if (er) throw er | |
net.createServer(function (conn) { | |
spawn(cmd, args, { stdio: [ conn, conn, fd ] }) | |
}).listen(80) | |
}) | |
// 7. like child_process.fork() | |
spawn(cmd, args, { stdio: [ 'ipc', 1, 2 ] }) | |
// 7a. like child_process.fork(..., {silent: true}) | |
spawn(cmd, args, { stdio: [ 'ipc', 'ignore', 'ignore' ] }) | |
// 8. interact with some silly unix utility that uses a bunch of weird | |
// stdio stuff. | |
// | |
// * stdin is a pipe | |
// * stdout is a JS stream object | |
// * stderr is mapped to the parent's stdout | |
// * fd=3 is a JS stream object | |
// * fd=4 is ignored | |
// * fd=5 is the parent's stdin (eg, for the user to type in a pass phrase) | |
// * fd=6 writes to an error log | |
// * fd=7 can receive file descriptors and handles. | |
var rw = createPipe() | |
var ipc = createPipe({ipc: true}) | |
fs.open("log.txt", function (er, fd) { | |
if (er) throw er | |
spawn(cmd, args, { stdio: [ rw, 'pipe', process.stdout, 'pipe', null, 0, fd, ipc ] }) | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@piscisaureus @bnoordhuis @igorzi Thoughts?