Skip to content
This repository has been archived by the owner on Apr 22, 2023. It is now read-only.

Commit

Permalink
child_process: expose UV_PROCESS_DETACHED as options.detached
Browse files Browse the repository at this point in the history
  • Loading branch information
AvianFlu authored and isaacs committed Jun 9, 2012
1 parent 5046f85 commit 4b021a3
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 5 deletions.
35 changes: 30 additions & 5 deletions doc/api/child_process.markdown
Expand Up @@ -249,7 +249,7 @@ there is no IPC channel keeping it alive. When calling this method the
* `customFds` {Array} **Deprecated** File descriptors for the child to use
for stdio. (See below)
* `env` {Object} Environment key-value pairs
* `setsid` {Boolean}
* `detached` {Boolean} The child will be a process group leader. (See below)
* return: {ChildProcess object}

Launches a new process with the given `command`, with command line arguments in `args`.
Expand Down Expand Up @@ -342,7 +342,7 @@ index corresponds to a fd in the child. The value is one of the following:

1. `'pipe'` - Create a pipe between the child process and the parent process.
The parent end of the pipe is exposed to the parent as a property on the
child_process object as `ChildProcess.stdio[fd]`. Pipes created for
`child_process` object as `ChildProcess.stdio[fd]`. Pipes created for
fds 0 - 2 are also available as ChildProcess.stdin, ChildProcess.stdout
and ChildProcess.stderr, respectively.
2. `'ipc'` - Create an IPC channel for passing messages/file descriptors
Expand Down Expand Up @@ -387,6 +387,34 @@ Example:
// startd-style interface.
spawn('prg', [], { stdio: ['pipe', null, null, null, 'pipe'] });

If the `detached` option is set, the child process will be made the leader of a
new process group. This makes it possible for the child to continue running
after the parent exits.

By default, the parent will wait for the detached child to exit. To prevent
the parent from waiting for a given `child`, use the `child.unref()` method,
and the parent's event loop will not include the child in its reference count.

Example of detaching a long-running process and redirecting its output to a
file:

var fs = require('fs'),
spawn = require('child_process').spawn,
out = fs.openSync('./out.log', 'a'),
err = fs.openSync('./out.log', 'a');

var child = spawn('prg', [], {
detached: 'true',
stdio: [ 'ignore', out, err ]
});

child.unref();

When using the `detached` option to start a long-running process, the process
will not stay running in the background unless it is provided with a `stdio`

This comment has been minimized.

Copy link
@OrangeDog

OrangeDog Jun 11, 2012

running in the background after the parent exits is the correct reading?

configuration that is not connected to the parent. If the parent's `stdio` is
inherited, the child will remain attached to the controlling terminal.

There is a deprecated option called `customFds` which allows one to specify
specific file descriptors for the stdio of the child process. This API was
not portable to all platforms and therefore removed.
Expand All @@ -409,7 +437,6 @@ See also: `child_process.exec()` and `child_process.fork()`
* `customFds` {Array} **Deprecated** File descriptors for the child to use
for stdio. (See above)
* `env` {Object} Environment key-value pairs
* `setsid` {Boolean}
* `encoding` {String} (Default: 'utf8')
* `timeout` {Number} (Default: 0)
* `maxBuffer` {Number} (Default: 200*1024)
Expand Down Expand Up @@ -467,7 +494,6 @@ the child process is killed.
* `customFds` {Array} **Deprecated** File descriptors for the child to use
for stdio. (See above)
* `env` {Object} Environment key-value pairs
* `setsid` {Boolean}
* `encoding` {String} (Default: 'utf8')
* `timeout` {Number} (Default: 0)
* `maxBuffer` {Number} (Default: 200*1024)
Expand All @@ -490,7 +516,6 @@ leaner than `child_process.exec`. It has the same options.
* `options` {Object}
* `cwd` {String} Current working directory of the child process
* `env` {Object} Environment key-value pairs
* `setsid` {Boolean}
* `encoding` {String} (Default: 'utf8')
* `timeout` {Number} (Default: 0)
* Return: ChildProcess object
Expand Down
5 changes: 5 additions & 0 deletions lib/child_process.js
Expand Up @@ -602,12 +602,17 @@ var spawn = exports.spawn = function(file, args, options) {
args: args,
cwd: options ? options.cwd : null,
windowsVerbatimArguments: !!(options && options.windowsVerbatimArguments),
detached: !!(options && options.detached),
envPairs: envPairs,
stdio: options ? options.stdio : null,
uid: options ? options.uid : null,
gid: options ? options.gid : null
});

if (options && options.detached) {
child.unref();

This comment has been minimized.

Copy link
@AndreasMadsen

AndreasMadsen Jun 11, 2012

Member

The doc says that I should call child.unref() to completely deattach the the child from its parent. However this automatically done here. Are I'm correct in assuming that it is necessary to call child.unref() twice from a core perspective or is this a bug (in doc or code).

@AvianFlu this is so awesome thanks.

This comment has been minimized.

Copy link
@isaacs

isaacs Jun 11, 2012

Ah, yes, that's a mistake on my part, I believe. I'll remove it. It'll be fixed in the next release.

}

return child;
};

Expand Down
5 changes: 5 additions & 0 deletions src/process_wrap.cc
Expand Up @@ -236,6 +236,11 @@ class ProcessWrap : public HandleWrap {
options.flags |= UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS;
}

//options.detached
if (js_options->Get(String::NewSymbol("detached"))->IsTrue()) {
options.flags |= UV_PROCESS_DETACHED;
}

int r = uv_spawn(uv_default_loop(), &wrap->process_, options);

if (r) {
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/child-process-persistent.js
@@ -0,0 +1 @@
setInterval(function () {}, 500);
38 changes: 38 additions & 0 deletions test/simple/test-child-process-detached.js
@@ -0,0 +1,38 @@
// 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 path = require('path');

var spawn = require('child_process').spawn;
var childPath = path.join(__dirname, '..', 'fixtures', 'child-process-persistent.js');

var child = spawn(process.execPath, [ childPath ], {
detached: true,
stdio: 'ignore'
});

process.on('exit', function () {
process.kill(child.pid);
assert.throws(process.kill(child.pid), Error);
});

3 comments on commit 4b021a3

@defunctzombie
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the 'ignore' option to stdio, input stream? Would it be better to use null?

@indutny
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'null' or 'undefined' are default values for stdio option, that means that for stdio < 3 (i.e. stdin, stdout, stderr) it'll create 'pipe' and for others 'ignore'.

@AvianFlu
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shtylman - The new stdio API for child processes allows for a couple of shorthands - if you pass only the string ignore, all three stdio will be redirected to /dev/null, or the windows equivalent. Where this test is concerned, it was used for simplicity.

Please sign in to comment.