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`? f50135a32e/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.
This commit is contained in:
erw7
2022-07-03 01:14:08 +09:00
committed by GitHub
parent c1b591dc8f
commit e11f3655fb
5 changed files with 19 additions and 0 deletions

View File

@@ -1075,4 +1075,6 @@ typedef enum {
// Only filled for Win32.
EXTERN char windowsVersion[20] INIT(= { 0 });
EXTERN int exit_need_delay INIT(= 0);
#endif // NVIM_GLOBALS_H