diff options
author | Thiago de Arruda <tpadilha84@gmail.com> | 2014-10-30 10:19:48 -0300 |
---|---|---|
committer | Thiago de Arruda <tpadilha84@gmail.com> | 2014-10-31 22:52:10 -0300 |
commit | c92d17b4aab9595f7606dd3509ad39b52ee780af (patch) | |
tree | d74cf1612fefa3c5886dc148767dcb0172c89c94 | |
parent | 25e26e0056c00bfb61f73a1ea4325257098c2c23 (diff) | |
download | rneovim-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.c | 1 | ||||
-rw-r--r-- | src/nvim/msgpack_rpc/channel.c | 1 | ||||
-rw-r--r-- | src/nvim/os/job.c | 88 | ||||
-rw-r--r-- | src/nvim/os/shell.c | 40 |
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; |