diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/nvim/eval.c | 48 | ||||
| -rw-r--r-- | src/nvim/event/libuv_process.c | 3 | ||||
| -rw-r--r-- | src/nvim/event/process.c | 23 | ||||
| -rw-r--r-- | src/nvim/event/process.h | 5 | 
4 files changed, 69 insertions, 10 deletions
| diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 7ac51d7bd7..8e8232b44d 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -7236,6 +7236,7 @@ static struct fst {    { "islocked",          1, 1, f_islocked },    { "items",             1, 1, f_items },    { "jobclose",          1, 2, f_jobclose }, +  { "jobpid",            1, 1, f_jobpid },    { "jobresize",         3, 3, f_jobresize },    { "jobsend",           2, 2, f_jobsend },    { "jobstart",          1, 2, f_jobstart }, @@ -11611,6 +11612,31 @@ static void f_jobclose(typval_T *argvars, typval_T *rettv)    }  } +// "jobpid(id)" function +static void f_jobpid(typval_T *argvars, typval_T *rettv) +{ +  rettv->v_type = VAR_NUMBER; +  rettv->vval.v_number = 0; + +  if (check_restricted() || check_secure()) { +    return; +  } + +  if (argvars[0].v_type != VAR_NUMBER) { +    EMSG(_(e_invarg)); +    return; +  } + +  TerminalJobData *data = find_job(argvars[0].vval.v_number); +  if (!data) { +    EMSG(_(e_invjob)); +    return; +  } + +  Process *proc = (Process *)&data->proc; +  rettv->vval.v_number = proc->pid; +} +  // "jobsend()" function  static void f_jobsend(typval_T *argvars, typval_T *rettv)  { @@ -11771,8 +11797,9 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv)    }    bool pty = job_opts && get_dict_number(job_opts, (uint8_t *)"pty") != 0; +  bool detach = job_opts && get_dict_number(job_opts, (uint8_t *)"detach") != 0;    TerminalJobData *data = common_job_init(argv, on_stdout, on_stderr, on_exit, -      job_opts, pty); +                                          job_opts, pty, detach);    Process *proc = (Process *)&data->proc;    if (pty) { @@ -16776,7 +16803,7 @@ static void f_termopen(typval_T *argvars, typval_T *rettv)    }    TerminalJobData *data = common_job_init(argv, on_stdout, on_stderr, on_exit, -      job_opts, true); +                                          job_opts, true, false);    data->proc.pty.width = curwin->w_width;    data->proc.pty.height = curwin->w_height;    data->proc.pty.term_name = xstrdup("xterm-256color"); @@ -21782,8 +21809,13 @@ char_u *do_string_sub(char_u *str, char_u *pat, char_u *sub, char_u *flags)    return ret;  } -static inline TerminalJobData *common_job_init(char **argv, ufunc_T *on_stdout, -    ufunc_T *on_stderr, ufunc_T *on_exit, dict_T *self, bool pty) +static inline TerminalJobData *common_job_init(char **argv, +                                               ufunc_T *on_stdout, +                                               ufunc_T *on_stderr, +                                               ufunc_T *on_exit, +                                               dict_T *self, +                                               bool pty, +                                               bool detach)  {    TerminalJobData *data = xcalloc(1, sizeof(TerminalJobData));    data->stopped = false; @@ -21806,6 +21838,7 @@ static inline TerminalJobData *common_job_init(char **argv, ufunc_T *on_stdout,    }    proc->cb = on_process_exit;    proc->events = data->events; +  proc->detach = detach;    return data;  } @@ -21833,8 +21866,13 @@ static inline bool common_job_callbacks(dict_T *vopts, ufunc_T **on_stdout,  static inline bool common_job_start(TerminalJobData *data, typval_T *rettv)  { -  data->refcount++;    Process *proc = (Process *)&data->proc; +  if (proc->type == kProcessTypePty && proc->detach) { +    EMSG2(_(e_invarg2), "terminal/pty job cannot be detached"); +    return false; +  } + +  data->refcount++;    char *cmd = xstrdup(proc->argv[0]);    if (!process_spawn(proc)) {      EMSG2(_(e_jobspawn), cmd); diff --git a/src/nvim/event/libuv_process.c b/src/nvim/event/libuv_process.c index 44305c69bc..9ef3468284 100644 --- a/src/nvim/event/libuv_process.c +++ b/src/nvim/event/libuv_process.c @@ -21,6 +21,9 @@ bool libuv_process_spawn(LibuvProcess *uvproc)    uvproc->uvopts.args = proc->argv;    uvproc->uvopts.flags = UV_PROCESS_WINDOWS_HIDE                    | UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS; +  if (proc->detach) { +      uvproc->uvopts.flags |= UV_PROCESS_DETACHED; +  }    uvproc->uvopts.exit_cb = exit_cb;    uvproc->uvopts.cwd = NULL;    uvproc->uvopts.env = NULL; diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c index 0336eb880a..e6012595fd 100644 --- a/src/nvim/event/process.c +++ b/src/nvim/event/process.c @@ -29,6 +29,7 @@      }                                                               \    } while (0) +static bool process_is_tearing_down = false;  bool process_spawn(Process *proc) FUNC_ATTR_NONNULL_ALL  { @@ -112,11 +113,22 @@ bool process_spawn(Process *proc) FUNC_ATTR_NONNULL_ALL  void process_teardown(Loop *loop) FUNC_ATTR_NONNULL_ALL  { +  process_is_tearing_down = true;    kl_iter(WatcherPtr, loop->children, current) {      Process *proc = (*current)->data; -    uv_kill(proc->pid, SIGTERM); -    proc->term_sent = true; -    process_stop(proc); +    if (proc->detach) { +      // Close handles to process without killing it. +      CREATE_EVENT(loop->events, process_close_handles, 1, proc); +    } else { +      if (proc->type == kProcessTypeUv) { +        uv_kill(proc->pid, SIGTERM); +        proc->term_sent = true; +        process_stop(proc); +      } else {  // kProcessTypePty +        process_close_streams(proc); +        pty_process_close_master((PtyProcess *)proc); +      } +    }    }    // Wait until all children exit @@ -303,6 +315,10 @@ static void decref(Process *proc)  static void process_close(Process *proc)    FUNC_ATTR_NONNULL_ARG(1)  { +  if (process_is_tearing_down && proc->detach && proc->closed) { +    // If a detached process dies while tearing down it might get closed twice. +    return; +  }    assert(!proc->closed);    proc->closed = true;    switch (proc->type) { @@ -333,6 +349,7 @@ static void on_process_exit(Process *proc)      DLOG("Stopping process kill timer");      uv_timer_stop(&loop->children_kill_timer);    } +    // 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 diff --git a/src/nvim/event/process.h b/src/nvim/event/process.h index 45edc46b95..e23c8ea60f 100644 --- a/src/nvim/event/process.h +++ b/src/nvim/event/process.h @@ -25,7 +25,7 @@ struct process {    Stream *in, *out, *err;    process_exit_cb cb;    internal_process_cb internal_exit_cb, internal_close_cb; -  bool closed, term_sent; +  bool closed, term_sent, detach;    Queue *events;  }; @@ -48,7 +48,8 @@ static inline Process process_init(Loop *loop, ProcessType type, void *data)      .closed = false,      .term_sent = false,      .internal_close_cb = NULL, -    .internal_exit_cb = NULL +    .internal_exit_cb = NULL, +    .detach = false    };  } | 
