diff options
author | erw7 <erw7.github@gmail.com> | 2022-07-03 01:14:08 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-07-02 09:14:08 -0700 |
commit | e11f3655fb3bbedc29e496db26a25e6c83d25baf (patch) | |
tree | 633e33e41e04d797de07fb20fb4d9145daf55bb4 /src/nvim/event/process.c | |
parent | c1b591dc8f99577c419192c7b34e3999758ed69f (diff) | |
download | rneovim-e11f3655fb3bbedc29e496db26a25e6c83d25baf.tar.gz rneovim-e11f3655fb3bbedc29e496db26a25e6c83d25baf.tar.bz2 rneovim-e11f3655fb3bbedc29e496db26a25e6c83d25baf.zip |
fix(jobs): deadlock in channel.c:exit_event #19082
In the rare case that exit_event is called from process_close_handles,
it stalls waiting for the process to exit (the routine is currently
underway to do just that). This causes `job_spec.lua` to sometimes
stall.
REJECTED IDEAS:
==============================================================
1. Currently `exit_event` is placed on `main_loop.fast_events`. Would the problem
be solved by using `main_loop.events` instead?
- A: Maybe, but it will cause other problems, such as queuing exit_event()
during "Press Enter..." prompt which may result in the event not being
processed, leading to another stall.
2. Can we avoid the timer?
- A: Using a timer is just the easiest way to queue a delayed event without
causing an infinite loop in the queue currently being processed.
3. Can we avoid the new `exit_need_delay` global...
1. by using `process_is_tearing_down` instead?
- A: Can't use `process_is_tearing_down` because its semantics are different.
2. by checking a similar condition as `process_teardown`? https://github.com/neovim/neovim/blob/f50135a32e11c535e1dc3a8e9460c5b4e640ee86/src/nvim/event/process.c#L141-L142
```
if (!process_is_tearing_down || (kl_empty(main_loop.children) && multiqueue_empty(main_loop.events))) {
uv_timer_start(&main_loop.exit_delay_timer, exit_delay_cb, 0, 0);
return;
}
```
- A: Tried but it did not work (other stalls occurred). Maybe
exit_event() is called from a source other than
process_close_handles() and is delayed, the delayed exit_event() will
be executed before main_loop.events is processed, resulting in an
infinite loop.
Diffstat (limited to 'src/nvim/event/process.c')
-rw-r--r-- | src/nvim/event/process.c | 2 |
1 files changed, 2 insertions, 0 deletions
diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c index 1ec11f1eb6..e029f778f6 100644 --- a/src/nvim/event/process.c +++ b/src/nvim/event/process.c @@ -386,11 +386,13 @@ static void process_close_handles(void **argv) { Process *proc = argv[0]; + exit_need_delay++; flush_stream(proc, &proc->out); flush_stream(proc, &proc->err); process_close_streams(proc); process_close(proc); + exit_need_delay--; } static void on_process_exit(Process *proc) |