aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/event/process.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/event/process.c')
-rw-r--r--src/nvim/event/process.c75
1 files changed, 45 insertions, 30 deletions
diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c
index c7360b8614..54dbc11a03 100644
--- a/src/nvim/event/process.c
+++ b/src/nvim/event/process.c
@@ -22,7 +22,7 @@
#define TERM_TIMEOUT 1000000000
#define KILL_TIMEOUT (TERM_TIMEOUT * 2)
-#define CLOSE_PROC_STREAM(proc, stream) \
+#define CLOSE_PROC_STREAM(proc, stream) \
do { \
if (proc->stream && !proc->stream->closed) { \
stream_close(proc->stream, NULL); \
@@ -76,6 +76,7 @@ bool process_spawn(Process *proc) FUNC_ATTR_NONNULL_ALL
if (proc->in) {
stream_init(NULL, proc->in, -1, (uv_stream_t *)&proc->in->uv.pipe, data);
+ proc->in->events = proc->events;
proc->in->internal_data = proc;
proc->in->internal_close_cb = on_process_stream_close;
proc->refcount++;
@@ -83,6 +84,7 @@ bool process_spawn(Process *proc) FUNC_ATTR_NONNULL_ALL
if (proc->out) {
stream_init(NULL, proc->out, -1, (uv_stream_t *)&proc->out->uv.pipe, data);
+ proc->out->events = proc->events;
proc->out->internal_data = proc;
proc->out->internal_close_cb = on_process_stream_close;
proc->refcount++;
@@ -90,6 +92,7 @@ bool process_spawn(Process *proc) FUNC_ATTR_NONNULL_ALL
if (proc->err) {
stream_init(NULL, proc->err, -1, (uv_stream_t *)&proc->err->uv.pipe, data);
+ proc->err->events = proc->events;
proc->err->internal_data = proc;
proc->err->internal_close_cb = on_process_stream_close;
proc->refcount++;
@@ -112,7 +115,7 @@ void process_teardown(Loop *loop) FUNC_ATTR_NONNULL_ALL
}
// Wait until all children exit
- LOOP_POLL_EVENTS_UNTIL(loop, -1, kl_empty(loop->children));
+ LOOP_PROCESS_EVENTS_UNTIL(loop, loop->events, -1, kl_empty(loop->children));
pty_process_teardown(loop);
}
@@ -154,11 +157,15 @@ int process_wait(Process *proc, int ms) FUNC_ATTR_NONNULL_ALL
// The default status is -1, which represents a timeout
int status = -1;
bool interrupted = false;
+ if (!proc->refcount) {
+ LOOP_PROCESS_EVENTS(proc->loop, proc->events, 0);
+ return proc->status;
+ }
// Increase refcount to stop the exit callback from being called(and possibly
// being freed) before we have a chance to get the status.
proc->refcount++;
- LOOP_POLL_EVENTS_UNTIL(proc->loop, ms,
+ LOOP_PROCESS_EVENTS_UNTIL(proc->loop, proc->events, ms,
// Until...
got_int || // interrupted by the user
proc->refcount == 1); // job exited
@@ -170,12 +177,12 @@ int process_wait(Process *proc, int ms) FUNC_ATTR_NONNULL_ALL
got_int = false;
process_stop(proc);
if (ms == -1) {
- // We can only return, if all streams/handles are closed and the job
-
+ // We can only return if all streams/handles are closed and the job
// exited.
- LOOP_POLL_EVENTS_UNTIL(proc->loop, -1, proc->refcount == 1);
+ LOOP_PROCESS_EVENTS_UNTIL(proc->loop, proc->events, -1,
+ proc->refcount == 1);
} else {
- loop_poll_events(proc->loop, 0);
+ LOOP_PROCESS_EVENTS(proc->loop, proc->events, 0);
}
}
@@ -184,6 +191,10 @@ int process_wait(Process *proc, int ms) FUNC_ATTR_NONNULL_ALL
// resources
status = interrupted ? -2 : proc->status;
decref(proc);
+ if (proc->events) {
+ // the decref call created an exit event, process it now
+ queue_process_events(proc->events);
+ }
} else {
proc->refcount--;
}
@@ -249,6 +260,18 @@ static void children_kill_cb(uv_timer_t *handle)
}
}
+static void process_close_event(void **argv)
+{
+ Process *proc = argv[0];
+ shell_free_argv(proc->argv);
+ if (proc->type == kProcessTypePty) {
+ xfree(((PtyProcess *)proc)->term_name);
+ }
+ if (proc->cb) {
+ proc->cb(proc, proc->status, proc->data);
+ }
+}
+
static void decref(Process *proc)
{
if (--proc->refcount != 0) {
@@ -263,16 +286,9 @@ static void decref(Process *proc)
break;
}
}
-
assert(node);
kl_shift_at(WatcherPtr, loop->children, node);
- shell_free_argv(proc->argv);
- if (proc->type == kProcessTypePty) {
- xfree(((PtyProcess *)proc)->term_name);
- }
- if (proc->cb) {
- proc->cb(proc, proc->status, proc->data);
- }
+ CREATE_EVENT(proc->events, process_close_event, 1, proc);
}
static void process_close(Process *proc)
@@ -292,28 +308,27 @@ static void process_close(Process *proc)
}
}
-static void on_process_exit(Process *proc)
+static void process_close_handles(void **argv)
{
- if (exiting) {
- on_process_exit_event((Event) {.data = proc});
- } else {
- loop_push_event(proc->loop,
- (Event) {.handler = on_process_exit_event, .data = proc}, false);
- }
+ Process *proc = argv[0];
+ process_close_streams(proc);
+ process_close(proc);
+}
+static void on_process_exit(Process *proc)
+{
Loop *loop = proc->loop;
- if (loop->children_stop_requests && !--loop->children_stop_requests) {
+ if (proc->stopped_time && loop->children_stop_requests
+ && !--loop->children_stop_requests) {
// Stop the timer if no more stop requests are pending
DLOG("Stopping process kill timer");
uv_timer_stop(&loop->children_kill_timer);
}
-}
-
-static void on_process_exit_event(Event event)
-{
- Process *proc = event.data;
- process_close_streams(proc);
- process_close(proc);
+ // Process handles are closed in the next event loop tick. This is done to
+ // give libuv more time to read data from the OS after the process exits(If
+ // process_close_streams is called with data still in the OS buffer, we lose
+ // it)
+ CREATE_EVENT(proc->events, process_close_handles, 1, proc);
}
static void on_process_stream_close(Stream *stream, void *data)