diff options
author | Gregory Anders <greg@gpanders.com> | 2021-08-28 09:58:27 -0600 |
---|---|---|
committer | Justin M. Keyes <justinkz@gmail.com> | 2021-08-31 06:53:06 -0700 |
commit | 3c081d028062f793b63b8689f854bbea30e15752 (patch) | |
tree | 336bf2b82126e5efa3d6f149d4a6026ef1a24d54 /src | |
parent | 55defa1a41baac65cd32dc499b330af9751d6c5b (diff) | |
download | rneovim-3c081d028062f793b63b8689f854bbea30e15752.tar.gz rneovim-3c081d028062f793b63b8689f854bbea30e15752.tar.bz2 rneovim-3c081d028062f793b63b8689f854bbea30e15752.zip |
fix(jobwait): always drain process event queues #15402
Problem:
jobwait() returns early if the job was stopped, but the job might have
pending callbacks on its event queue which are required to complete its
teardown. State such as term->closed might not be updated yet (by the
pending callbacks), so codepaths such as :bdelete think the job is still
running.
Solution:
Always flush the job's event queue before returning from jobwait().
ref #15349
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/eval/funcs.c | 11 |
1 files changed, 8 insertions, 3 deletions
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 8a1258efd4..99f9f17e0a 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -5404,14 +5404,19 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv, FunPtr fptr) TV_LIST_ITER_CONST(args, arg, { Channel *chan = NULL; if (TV_LIST_ITEM_TV(arg)->v_type != VAR_NUMBER - || !(chan = find_job(TV_LIST_ITEM_TV(arg)->vval.v_number, false))) { + || !(chan = find_channel(TV_LIST_ITEM_TV(arg)->vval.v_number)) + || chan->streamtype != kChannelStreamProc) { + jobs[i] = NULL; // Invalid job. + } else if (process_is_stopped(&chan->stream.proc)) { + // Job is stopped but not fully destroyed. + // Ensure all callbacks on its event queue are executed. #15402 + process_wait(&chan->stream.proc, -1, NULL); jobs[i] = NULL; // Invalid job. } else { jobs[i] = chan; channel_incref(chan); if (chan->stream.proc.status < 0) { - // Process any pending events on the job's queue before temporarily - // replacing it. + // Flush any events in the job's queue before temporarily replacing it. multiqueue_process_events(chan->events); multiqueue_replace_parent(chan->events, waiting_jobs); } |