diff options
Diffstat (limited to 'src/nvim/event/process.c')
-rw-r--r-- | src/nvim/event/process.c | 87 |
1 files changed, 46 insertions, 41 deletions
diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c index dc7886469b..8371d3cd48 100644 --- a/src/nvim/event/process.c +++ b/src/nvim/event/process.c @@ -1,3 +1,6 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check +// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com + #include <assert.h> #include <stdlib.h> @@ -11,15 +14,16 @@ #include "nvim/event/libuv_process.h" #include "nvim/os/pty_process.h" #include "nvim/globals.h" +#include "nvim/macros.h" #include "nvim/log.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "event/process.c.generated.h" #endif -// Time (ns) for a process to exit cleanly before we send TERM/KILL. -#define TERM_TIMEOUT 1000000000 -#define KILL_TIMEOUT (TERM_TIMEOUT * 2) +// Time for a process to exit cleanly before we send KILL. +// For pty processes SIGTERM is sent first (in case SIGHUP was not enough). +#define KILL_TIMEOUT_MS 2000 #define CLOSE_PROC_STREAM(proc, stream) \ do { \ @@ -30,7 +34,8 @@ static bool process_is_tearing_down = false; -bool process_spawn(Process *proc) FUNC_ATTR_NONNULL_ALL +/// @returns zero on success, or negative error code +int process_spawn(Process *proc) FUNC_ATTR_NONNULL_ALL { if (proc->in) { uv_pipe_init(&proc->loop->uv, &proc->in->uv.pipe, 0); @@ -44,19 +49,19 @@ bool process_spawn(Process *proc) FUNC_ATTR_NONNULL_ALL uv_pipe_init(&proc->loop->uv, &proc->err->uv.pipe, 0); } - bool success; + int status; switch (proc->type) { case kProcessTypeUv: - success = libuv_process_spawn((LibuvProcess *)proc); + status = libuv_process_spawn((LibuvProcess *)proc); break; case kProcessTypePty: - success = pty_process_spawn((PtyProcess *)proc); + status = pty_process_spawn((PtyProcess *)proc); break; default: abort(); } - if (!success) { + if (status) { if (proc->in) { uv_close((uv_handle_t *)&proc->in->uv.pipe, NULL); } @@ -74,11 +79,12 @@ bool process_spawn(Process *proc) FUNC_ATTR_NONNULL_ALL } shell_free_argv(proc->argv); proc->status = -1; - return false; + return status; } if (proc->in) { - stream_init(NULL, proc->in, -1, (uv_stream_t *)&proc->in->uv.pipe); + stream_init(NULL, proc->in, -1, + STRUCT_CAST(uv_stream_t, &proc->in->uv.pipe)); proc->in->events = proc->events; proc->in->internal_data = proc; proc->in->internal_close_cb = on_process_stream_close; @@ -86,7 +92,8 @@ 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); + stream_init(NULL, proc->out, -1, + STRUCT_CAST(uv_stream_t, &proc->out->uv.pipe)); proc->out->events = proc->events; proc->out->internal_data = proc; proc->out->internal_close_cb = on_process_stream_close; @@ -94,7 +101,8 @@ 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); + stream_init(NULL, proc->err, -1, + STRUCT_CAST(uv_stream_t, &proc->err->uv.pipe)); proc->err->events = proc->events; proc->err->internal_data = proc; proc->err->internal_close_cb = on_process_stream_close; @@ -105,7 +113,7 @@ bool process_spawn(Process *proc) FUNC_ATTR_NONNULL_ALL proc->internal_close_cb = decref; proc->refcount++; kl_push(WatcherPtr, proc->loop->children, proc); - return true; + return 0; } void process_teardown(Loop *loop) FUNC_ATTR_NONNULL_ALL @@ -117,8 +125,6 @@ void process_teardown(Loop *loop) FUNC_ATTR_NONNULL_ALL // Close handles to process without killing it. CREATE_EVENT(loop->events, process_close_handles, 1, proc); } else { - uv_kill(proc->pid, SIGTERM); - proc->term_sent = true; process_stop(proc); } } @@ -155,19 +161,16 @@ void process_close_err(Process *proc) FUNC_ATTR_NONNULL_ALL /// Synchronously wait for a process to finish /// -/// @param process The Process instance -/// @param ms Number of milliseconds to wait, 0 for not waiting, -1 for -/// waiting until the process quits. -/// @return returns the status code of the exited process. -1 if the process is -/// still running and the `timeout` has expired. Note that this is -/// indistinguishable from the process returning -1 by itself. Which -/// is possible on some OS. Returns -2 if an user has interruped the -/// wait. +/// @param process Process instance +/// @param ms Time in milliseconds to wait for the process. +/// 0 for no wait. -1 to wait until the process quits. +/// @return Exit code of the process. +/// -1 if the timeout expired while the process is still running. +/// -2 if the user interruped the wait. int process_wait(Process *proc, int ms, MultiQueue *events) FUNC_ATTR_NONNULL_ARG(1) { - // The default status is -1, which represents a timeout - int status = -1; + int status = -1; // default bool interrupted = false; if (!proc->refcount) { status = proc->status; @@ -179,8 +182,8 @@ int process_wait(Process *proc, int ms, MultiQueue *events) events = proc->events; } - // Increase refcount to stop the exit callback from being called(and possibly - // being freed) before we have a chance to get the status. + // Increase refcount to stop the exit callback from being called (and possibly + // freed) before we have a chance to get the status. proc->refcount++; LOOP_PROCESS_EVENTS_UNTIL(proc->loop, events, ms, // Until... @@ -230,9 +233,10 @@ void process_stop(Process *proc) FUNC_ATTR_NONNULL_ALL switch (proc->type) { case kProcessTypeUv: // Close the process's stdin. If the process doesn't close its own - // stdout/stderr, they will be closed when it exits(possibly due to being - // terminated after a timeout) + // stdout/stderr, they will be closed when it exits (voluntarily or not). process_close_in(proc); + ILOG("Sending SIGTERM to pid %d", proc->pid); + uv_kill(proc->pid, SIGTERM); break; case kProcessTypePty: // close all streams for pty processes to send SIGHUP to the process @@ -246,9 +250,10 @@ void process_stop(Process *proc) FUNC_ATTR_NONNULL_ALL Loop *loop = proc->loop; if (!loop->children_stop_requests++) { // When there's at least one stop request pending, start a timer that - // will periodically check if a signal should be send to a to the job - DLOG("Starting job kill timer"); - uv_timer_start(&loop->children_kill_timer, children_kill_cb, 100, 100); + // will periodically check if a signal should be send to the job. + ILOG("Starting job kill timer"); + uv_timer_start(&loop->children_kill_timer, children_kill_cb, + KILL_TIMEOUT_MS, KILL_TIMEOUT_MS); } } @@ -264,15 +269,15 @@ static void children_kill_cb(uv_timer_t *handle) if (!proc->stopped_time) { continue; } - uint64_t elapsed = now - proc->stopped_time; - - if (!proc->term_sent && elapsed >= TERM_TIMEOUT) { - ILOG("Sending SIGTERM to pid %d", proc->pid); - uv_kill(proc->pid, SIGTERM); - proc->term_sent = true; - } else if (elapsed >= KILL_TIMEOUT) { - ILOG("Sending SIGKILL to pid %d", proc->pid); - uv_kill(proc->pid, SIGKILL); + uint64_t elapsed = (now - proc->stopped_time) / 1000000 + 1; + + if (elapsed >= KILL_TIMEOUT_MS) { + int sig = proc->type == kProcessTypePty && elapsed < KILL_TIMEOUT_MS * 2 + ? SIGTERM + : SIGKILL; + ILOG("Sending %s to pid %d", sig == SIGTERM ? "SIGTERM" : "SIGKILL", + proc->pid); + uv_kill(proc->pid, sig); } } } |