mirror of
https://github.com/neovim/neovim.git
synced 2024-09-17 20:58:20 -04:00
fix(jobwait): always drain process event queues #15970
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 Co-authored-by: Gregory Anders <greg@gpanders.com>
This commit is contained in:
parent
b5276b36d4
commit
d8ccee30b0
@ -13,7 +13,7 @@ from the connected program.
|
||||
Terminal buffers behave like normal buffers, except:
|
||||
- With 'modifiable', lines can be edited but not deleted.
|
||||
- 'scrollback' controls how many lines are kept.
|
||||
- Output is followed if the cursor is on the last line.
|
||||
- Output is followed ("tailed") if cursor is on the last line.
|
||||
- 'modified' is the default. You can set 'nomodified' to avoid a warning when
|
||||
closing the terminal buffer.
|
||||
- 'bufhidden' defaults to "hide".
|
||||
|
@ -5328,14 +5328,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);
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ local eq, neq = helpers.eq, helpers.neq
|
||||
local write_file = helpers.write_file
|
||||
local command= helpers.command
|
||||
local exc_exec = helpers.exc_exec
|
||||
local matches = helpers.matches
|
||||
|
||||
describe(':terminal buffer', function()
|
||||
local screen
|
||||
@ -259,6 +260,14 @@ describe(':terminal buffer', function()
|
||||
eq('Vim(wqall):E948: Job still running', exc_exec('wqall'))
|
||||
end)
|
||||
|
||||
it('stops running jobs with :quit', function()
|
||||
-- Open in a new window to avoid terminating the nvim instance
|
||||
command('split')
|
||||
command('terminal')
|
||||
command('set nohidden')
|
||||
command('quit')
|
||||
end)
|
||||
|
||||
it('does not segfault when pasting empty buffer #13955', function()
|
||||
feed_command('terminal')
|
||||
feed('<c-\\><c-n>')
|
||||
|
Loading…
Reference in New Issue
Block a user