job: Replace by a better process abstraction layer

- New libuv/pty process abstraction with simplified API and no globals.
- Remove nvim/os/job*. Jobs are now a concept that apply only to programs
  spawned by vimscript job* functions.
- Refactor shell.c/channel.c to use the new module, which brings a number of
  advantages:
  - Simplified API, less code
  - No slots in the user job table are used
  - Not possible to acidentally receive data from vimscript
- Implement job table in eval.c, which is now a hash table with unilimited job
  slots and unique job ids.
This commit is contained in:
Thiago de Arruda
2015-07-17 00:32:07 -03:00
parent 9d8d2b7fa8
commit aa9cb48bf0
21 changed files with 791 additions and 1016 deletions

View File

@@ -9,7 +9,7 @@
#include "nvim/lib/kvec.h"
#include "nvim/log.h"
#include "nvim/event/loop.h"
#include "nvim/os/job.h"
#include "nvim/event/uv_process.h"
#include "nvim/event/rstream.h"
#include "nvim/os/shell.h"
#include "nvim/os/signal.h"
@@ -204,17 +204,15 @@ static int do_os_system(char **argv,
char prog[MAXPATHL];
xstrlcpy(prog, argv[0], MAXPATHL);
int status;
JobOptions opts = JOB_OPTIONS_INIT;
opts.argv = argv;
opts.data = &buf;
opts.writable = input != NULL;
opts.stdout_cb = data_cb;
opts.stderr_cb = data_cb;
opts.exit_cb = NULL;
Job *job = job_start(opts, &status);
if (status <= 0) {
Stream in, out, err;
UvProcess uvproc = uv_process_init(&buf);
Process *proc = &uvproc.process;
proc->argv = argv;
proc->in = input != NULL ? &in : NULL;
proc->out = &out;
proc->err = &err;
if (!process_spawn(&loop, proc)) {
loop_poll_events(&loop, 0);
// Failed, probably due to `sh` not being executable
if (!silent) {
MSG_PUTS(_("\nCannot execute "));
@@ -224,28 +222,32 @@ static int do_os_system(char **argv,
return -1;
}
if (input != NULL) {
wstream_init(proc->in, 0);
}
rstream_init(proc->out, 0);
rstream_start(proc->out, data_cb);
rstream_init(proc->err, 0);
rstream_start(proc->err, data_cb);
// write the input, if any
if (input) {
WBuffer *input_buffer = wstream_new_buffer((char *) input, len, 1, NULL);
if (!job_write(job, input_buffer)) {
// couldn't write, stop the job and tell the user about it
job_stop(job);
if (!wstream_write(&in, input_buffer)) {
// couldn't write, stop the process and tell the user about it
process_stop(proc);
return -1;
}
// close the input stream after everything is written
job_write_cb(job, shell_write_cb);
} else {
// close the input stream, let the process know that no more input is
// coming
job_close_in(job);
wstream_set_write_cb(&in, shell_write_cb);
}
// invoke busy_start here so event_poll_until wont change the busy state for
// the UI
ui_busy_start();
ui_flush();
status = job_wait(job, -1);
int status = process_wait(proc, -1);
ui_busy_stop();
// prepare the out parameters if requested
@@ -285,8 +287,7 @@ static void dynamic_buffer_ensure(DynamicBuffer *buf, size_t desired)
static void system_data_cb(Stream *stream, RBuffer *buf, void *data, bool eof)
{
Job *job = data;
DynamicBuffer *dbuf = job_data(job);
DynamicBuffer *dbuf = data;
size_t nread = buf->size;
dynamic_buffer_ensure(dbuf, dbuf->len + nread + 1);
@@ -472,6 +473,5 @@ static size_t write_output(char *output, size_t remaining, bool to_buffer,
static void shell_write_cb(Stream *stream, void *data, int status)
{
Job *job = data;
job_close_in(job);
stream_close(stream, NULL);
}