aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThiago de Arruda <tpadilha84@gmail.com>2014-10-30 10:19:48 -0300
committerThiago de Arruda <tpadilha84@gmail.com>2014-10-31 22:52:10 -0300
commitc92d17b4aab9595f7606dd3509ad39b52ee780af (patch)
treed74cf1612fefa3c5886dc148767dcb0172c89c94
parent25e26e0056c00bfb61f73a1ea4325257098c2c23 (diff)
downloadrneovim-c92d17b4aab9595f7606dd3509ad39b52ee780af.tar.gz
rneovim-c92d17b4aab9595f7606dd3509ad39b52ee780af.tar.bz2
rneovim-c92d17b4aab9595f7606dd3509ad39b52ee780af.zip
job: Let job_start callers to selectively ignore stdio
Passing NULL as the callback for stdout/stderr will result in job_start ignoring stdout/stderr, respectively. A 'writable' boolean argument was also added, and when false `job_start` will ignore stdin. Also, refactor os_system to allow passing NULL as the `output` argument.
-rw-r--r--src/nvim/eval.c1
-rw-r--r--src/nvim/msgpack_rpc/channel.c1
-rw-r--r--src/nvim/os/job.c88
-rw-r--r--src/nvim/os/shell.c40
4 files changed, 85 insertions, 45 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index d0af4b8249..6b6f008a44 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -10675,6 +10675,7 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv)
job_start(argv,
xstrdup((char *)argvars[0].vval.v_string),
+ true,
on_job_stdout,
on_job_stderr,
on_job_exit,
diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c
index 43bed54b2c..8d74921562 100644
--- a/src/nvim/msgpack_rpc/channel.c
+++ b/src/nvim/msgpack_rpc/channel.c
@@ -119,6 +119,7 @@ uint64_t channel_from_job(char **argv)
int status;
channel->data.job = job_start(argv,
channel,
+ true,
job_out,
job_err,
job_exit,
diff --git a/src/nvim/os/job.c b/src/nvim/os/job.c
index bbf8006ab6..4fa442fe76 100644
--- a/src/nvim/os/job.c
+++ b/src/nvim/os/job.c
@@ -136,10 +136,12 @@ void job_teardown(void)
/// @param argv Argument vector for the process. The first item is the
/// executable to run.
/// @param data Caller data that will be associated with the job
+/// @param writable If true the job stdin will be available for writing with
+/// job_write, otherwise it will be redirected to /dev/null
/// @param stdout_cb Callback that will be invoked when data is available
-/// on stdout
+/// on stdout. If NULL stdout will be redirected to /dev/null.
/// @param stderr_cb Callback that will be invoked when data is available
-/// on stderr
+/// on stderr. If NULL stderr will be redirected to /dev/null.
/// @param job_exit_cb Callback that will be invoked when the job exits
/// @param maxmem Maximum amount of memory used by the job WStream
/// @param[out] status The job id if the job started successfully, 0 if the job
@@ -147,6 +149,7 @@ void job_teardown(void)
/// @return The job pointer if the job started successfully, NULL otherwise
Job *job_start(char **argv,
void *data,
+ bool writable,
rstream_cb stdout_cb,
rstream_cb stderr_cb,
job_exit_cb job_exit_cb,
@@ -174,7 +177,7 @@ Job *job_start(char **argv,
job->id = i + 1;
*status = job->id;
job->status = -1;
- job->refcount = 4;
+ job->refcount = 1;
job->data = data;
job->stdout_cb = stdout_cb;
job->stderr_cb = stderr_cb;
@@ -193,45 +196,76 @@ Job *job_start(char **argv,
job->proc_stdin.data = NULL;
job->proc_stdout.data = NULL;
job->proc_stderr.data = NULL;
+ job->in = NULL;
+ job->out = NULL;
+ job->err = NULL;
// Initialize the job std{in,out,err}
- uv_pipe_init(uv_default_loop(), &job->proc_stdin, 0);
- job->stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
- job->stdio[0].data.stream = (uv_stream_t *)&job->proc_stdin;
+ job->stdio[0].flags = UV_IGNORE;
+ job->stdio[1].flags = UV_IGNORE;
+ job->stdio[2].flags = UV_IGNORE;
+
+ if (writable) {
+ uv_pipe_init(uv_default_loop(), &job->proc_stdin, 0);
+ job->stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
+ job->stdio[0].data.stream = (uv_stream_t *)&job->proc_stdin;
+ handle_set_job((uv_handle_t *)&job->proc_stdin, job);
+ job->refcount++;
+ }
- uv_pipe_init(uv_default_loop(), &job->proc_stdout, 0);
- job->stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
- job->stdio[1].data.stream = (uv_stream_t *)&job->proc_stdout;
+ if (stdout_cb) {
+ uv_pipe_init(uv_default_loop(), &job->proc_stdout, 0);
+ job->stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ job->stdio[1].data.stream = (uv_stream_t *)&job->proc_stdout;
+ handle_set_job((uv_handle_t *)&job->proc_stdout, job);
+ job->refcount++;
+ }
- uv_pipe_init(uv_default_loop(), &job->proc_stderr, 0);
- job->stdio[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
- job->stdio[2].data.stream = (uv_stream_t *)&job->proc_stderr;
+ if (stderr_cb) {
+ uv_pipe_init(uv_default_loop(), &job->proc_stderr, 0);
+ job->stdio[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ job->stdio[2].data.stream = (uv_stream_t *)&job->proc_stderr;
+ handle_set_job((uv_handle_t *)&job->proc_stderr, job);
+ job->refcount++;
+ }
- // Give all handles a reference to the job
handle_set_job((uv_handle_t *)&job->proc, job);
- handle_set_job((uv_handle_t *)&job->proc_stdin, job);
- handle_set_job((uv_handle_t *)&job->proc_stdout, job);
- handle_set_job((uv_handle_t *)&job->proc_stderr, job);
// Spawn the job
if (uv_spawn(uv_default_loop(), &job->proc, &job->proc_opts) != 0) {
- uv_close((uv_handle_t *)&job->proc_stdin, NULL);
- uv_close((uv_handle_t *)&job->proc_stdout, NULL);
- uv_close((uv_handle_t *)&job->proc_stderr, NULL);
+ if (writable) {
+ uv_close((uv_handle_t *)&job->proc_stdin, close_cb);
+ }
+ if (stdout_cb) {
+ uv_close((uv_handle_t *)&job->proc_stdout, close_cb);
+ }
+ if (stderr_cb) {
+ uv_close((uv_handle_t *)&job->proc_stderr, close_cb);
+ }
+ uv_close((uv_handle_t *)&job->proc, close_cb);
event_poll(0);
+ // Manually invoke the close_cb to free the job resources
*status = -1;
return NULL;
}
- job->in = wstream_new(maxmem);
- wstream_set_stream(job->in, (uv_stream_t *)&job->proc_stdin);
+ if (writable) {
+ job->in = wstream_new(maxmem);
+ wstream_set_stream(job->in, (uv_stream_t *)&job->proc_stdin);
+ }
+
// Start the readable streams
- job->out = rstream_new(read_cb, rbuffer_new(JOB_BUFFER_SIZE), job);
- job->err = rstream_new(read_cb, rbuffer_new(JOB_BUFFER_SIZE), job);
- rstream_set_stream(job->out, (uv_stream_t *)&job->proc_stdout);
- rstream_set_stream(job->err, (uv_stream_t *)&job->proc_stderr);
- rstream_start(job->out);
- rstream_start(job->err);
+ if (stdout_cb) {
+ job->out = rstream_new(read_cb, rbuffer_new(JOB_BUFFER_SIZE), job);
+ rstream_set_stream(job->out, (uv_stream_t *)&job->proc_stdout);
+ rstream_start(job->out);
+ }
+
+ if (stderr_cb) {
+ job->err = rstream_new(read_cb, rbuffer_new(JOB_BUFFER_SIZE), job);
+ rstream_set_stream(job->err, (uv_stream_t *)&job->proc_stderr);
+ rstream_start(job->err);
+ }
// Save the job to the table
table[i] = job;
diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c
index d5464f7975..ef95946b68 100644
--- a/src/nvim/os/shell.c
+++ b/src/nvim/os/shell.c
@@ -258,8 +258,8 @@ int os_call_shell(char_u *cmd, ShellOpts opts, char_u *extra_shell_arg)
/// @param len The length of the input buffer (not used if `input` == NULL)
/// @param[out] output A pointer to to a location where the output will be
/// allocated and stored. Will point to NULL if the shell
-/// command did not output anything. NOTE: it's not
-/// allowed to pass NULL yet
+/// command did not output anything. If NULL is passed,
+/// the shell output will be ignored.
/// @param[out] nread the number of bytes in the returned buffer (if the
/// returned buffer is not NULL)
/// @return the return code of the process, -1 if the process couldn't be
@@ -268,7 +268,7 @@ int os_system(const char *cmd,
const char *input,
size_t len,
char **output,
- size_t *nread) FUNC_ATTR_NONNULL_ARG(1, 4)
+ size_t *nread) FUNC_ATTR_NONNULL_ARG(1)
{
// the output buffer
dyn_buffer_t buf;
@@ -279,8 +279,9 @@ int os_system(const char *cmd,
int i;
Job *job = job_start(argv,
&buf,
- system_data_cb,
- system_data_cb,
+ input != NULL,
+ output ? system_data_cb : NULL,
+ output ? system_data_cb : NULL,
NULL,
0,
&i);
@@ -300,25 +301,28 @@ int os_system(const char *cmd,
job_stop(job);
return -1;
}
+ // close the input stream, let the process know that no more input is
+ // coming
+ job_close_in(job);
}
- // close the input stream, let the process know that no more input is coming
- job_close_in(job);
int status = job_wait(job, -1);
// prepare the out parameters if requested
- if (buf.len == 0) {
- // no data received from the process, return NULL
- *output = NULL;
- free(buf.data);
- } else {
- // NUL-terminate to make the output directly usable as a C string
- buf.data[buf.len] = NUL;
- *output = buf.data;
- }
+ if (output) {
+ if (buf.len == 0) {
+ // no data received from the process, return NULL
+ *output = NULL;
+ free(buf.data);
+ } else {
+ // NUL-terminate to make the output directly usable as a C string
+ buf.data[buf.len] = NUL;
+ *output = buf.data;
+ }
- if (nread) {
- *nread = buf.len;
+ if (nread) {
+ *nread = buf.len;
+ }
}
return status;