]> granicus.if.org Git - vim/commitdiff
patch 8.2.3941: SIGTSTP is not handled v8.2.3941
authordbivolaru <dbivolaru@jacobs-alumni.de>
Wed, 29 Dec 2021 19:41:47 +0000 (19:41 +0000)
committerBram Moolenaar <Bram@vim.org>
Wed, 29 Dec 2021 19:41:47 +0000 (19:41 +0000)
Problem:    SIGTSTP is not handled.
Solution:   Handle SIGTSTP like pressing CTRL-Z. (closes #9422)

runtime/doc/autocmd.txt
src/ex_docmd.c
src/os_unix.c
src/proto/ex_docmd.pro
src/testdir/test_signals.vim
src/version.c

index e620f5c04abe2d5fcf82f32a945b2a37e8952901..c1aee0ef8be2535571f2eba0d83405e026caed6a 100644 (file)
@@ -1279,8 +1279,8 @@ VimResume                 When the Vim instance is resumed after being
        :autocmd VimResume * checktime
 <                                                      *VimSuspend*
 VimSuspend                     When the Vim instance is suspended.  Only when
-                               CTRL-Z was typed inside Vim, not when the
-                               SIGSTOP or SIGTSTP signal was sent to Vim.
+                               CTRL-Z was typed inside Vim, or when the SIGTSTP
+                               signal was sent to Vim, but not for SIGSTOP.
                                                        *WinClosed*
 WinClosed                      After closing a window.  The pattern is
                                matched against the |window-ID|.  Both
index 8f4f4aea5eeabbf0ead844fdc7704f044a425dd1..12824a9dc9bd255536ce250270777cfb6c1d8980 100644 (file)
@@ -109,7 +109,6 @@ static void ex_pedit(exarg_T *eap);
 # define ex_pedit              ex_ni
 #endif
 static void    ex_hide(exarg_T *eap);
-static void    ex_stop(exarg_T *eap);
 static void    ex_exit(exarg_T *eap);
 static void    ex_print(exarg_T *eap);
 #ifdef FEAT_BYTEOFF
@@ -6200,7 +6199,7 @@ ex_hide(exarg_T *eap UNUSED)
 /*
  * ":stop" and ":suspend": Suspend Vim.
  */
-    static void
+    void
 ex_stop(exarg_T *eap)
 {
     /*
index 77f35db95836dac871f7d9d471cac58ade38cbd5..e24c09f4aae831394a9a00430b10ea49f50d5d0e 100644 (file)
@@ -157,6 +157,11 @@ static void handle_resize(void);
 #if defined(SIGWINCH)
 static RETSIGTYPE sig_winch SIGPROTOARG;
 #endif
+#if defined(SIGTSTP)
+static RETSIGTYPE sig_tstp SIGPROTOARG;
+// volatile because it is used in signal handler sig_tstp() and sigcont_handler().
+static volatile sig_atomic_t in_mch_suspend = FALSE;
+#endif
 #if defined(SIGINT)
 static RETSIGTYPE catch_sigint SIGPROTOARG;
 #endif
@@ -197,6 +202,8 @@ static int save_patterns(int num_pat, char_u **pat, int *num_file, char_u ***fil
 
 // volatile because it is used in signal handler sig_winch().
 static volatile sig_atomic_t do_resize = FALSE;
+// volatile because it is used in signal handler sig_tstp().
+static volatile sig_atomic_t got_tstp = FALSE;
 static char_u  *extra_shell_arg = NULL;
 static int     show_shell_mess = TRUE;
 // volatile because it is used in signal handler deathtrap().
@@ -851,6 +858,24 @@ sig_winch SIGDEFARG(sigarg)
 }
 #endif
 
+#if defined(SIGTSTP)
+    static RETSIGTYPE
+sig_tstp SIGDEFARG(sigarg)
+{
+    // Second time we get called we actually need to suspend
+    if (in_mch_suspend)
+    {
+       signal(SIGTSTP, ignore_sigtstp ? SIG_IGN : SIG_DFL);
+       raise(sigarg);
+    }
+
+    // this is not required on all systems, but it doesn't hurt anybody
+    signal(SIGTSTP, (RETSIGTYPE (*)())sig_tstp);
+    got_tstp = TRUE;
+    SIGRETURN;
+}
+#endif
+
 #if defined(SIGINT)
     static RETSIGTYPE
 catch_sigint SIGDEFARG(sigarg)
@@ -1158,7 +1183,6 @@ after_sigcont(void)
 
 #if defined(SIGCONT)
 static RETSIGTYPE sigcont_handler SIGPROTOARG;
-static volatile sig_atomic_t in_mch_suspend = FALSE;
 
 /*
  * With multi-threading, suspending might not work immediately.  Catch the
@@ -1353,7 +1377,7 @@ set_signals(void)
 
 #ifdef SIGTSTP
     // See mch_init() for the conditions under which we ignore SIGTSTP.
-    signal(SIGTSTP, ignore_sigtstp ? SIG_IGN : SIG_DFL);
+    signal(SIGTSTP, ignore_sigtstp ? SIG_IGN : (RETSIGTYPE (*)())sig_tstp);
 #endif
 #if defined(SIGCONT)
     signal(SIGCONT, sigcont_handler);
@@ -6386,6 +6410,15 @@ select_eintr:
 # ifdef EINTR
        if (ret == -1 && errno == EINTR)
        {
+           // Check whether the EINTR is caused by SIGTSTP
+           if (got_tstp && !in_mch_suspend)
+           {
+               exarg_T ea;
+               ea.forceit = TRUE;
+               ex_stop(&ea);
+               got_tstp = FALSE;
+           }
+
            // Check whether window has been resized, EINTR may be caused by
            // SIGWINCH.
            if (do_resize)
@@ -7176,7 +7209,7 @@ gpm_open(void)
            // we are going to suspend or starting an external process
            // so we shouldn't  have problem with this
 # ifdef SIGTSTP
-           signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
+           signal(SIGTSTP, restricted ? SIG_IGN : (RETSIGTYPE (*)())sig_tstp);
 # endif
            return 1; // succeed
        }
index d88b8a3e58108f6d2c10e4cf9a5a07d8101b2ef6..0fed2f02df9c71025407e990b71e8b6a61db97e4 100644 (file)
@@ -40,6 +40,7 @@ int before_quit_autocmds(win_T *wp, int quit_all, int forceit);
 void ex_quit(exarg_T *eap);
 void tabpage_close(int forceit);
 void tabpage_close_other(tabpage_T *tp, int forceit);
+void ex_stop(exarg_T *eap);
 void handle_drop(int filec, char_u **filev, int split, void (*callback)(void *), void *cookie);
 void handle_any_postponed_drop(void);
 void ex_splitview(exarg_T *eap);
index 72fd024332558da22d88982d21fd3bf0fd53f494..d3a4d89cec5fd439a5d96650827e1e64adc6e74d 100644 (file)
@@ -105,6 +105,58 @@ func Test_signal_INT()
   call StopVimInTerminal(buf)
 endfunc
 
+" Test signal TSTP. Handler sets got_tstp.
+func Test_signal_TSTP()
+  CheckRunVimInTerminal
+  if !HasSignal('TSTP')
+    throw 'Skipped: TSTP signal not supported'
+  endif
+
+  " Skip the test when running with valgrind as signal TSTP is not received
+  " somehow by Vim when running with valgrind.
+  let cmd = GetVimCommand()
+  if cmd =~ 'valgrind'
+    throw 'Skipped: cannot test signal TSTP with valgrind'
+  endif
+
+  " If test fails once, it can leave temporary files and trying to rerun
+  " the test would then fail again if they are not deleted first.
+  call delete('.Xsig_TERM.swp')
+  call delete('XsetupAucmd')
+  call delete('XautoOut')
+  let lines =<< trim END
+    au VimSuspend * call writefile(["VimSuspend triggered"], "XautoOut", "as")
+    au VimResume * call writefile(["VimResume triggered"], "XautoOut", "as")
+  END
+  call writefile(lines, 'XsetupAucmd')
+
+  let buf = RunVimInTerminal('-S XsetupAucmd Xsig_TERM', {'rows': 6})
+  let pid_vim = term_getjob(buf)->job_info().process
+
+  call term_sendkeys(buf, ":call setline(1, 'foo')\n")
+  call WaitForAssert({-> assert_equal('foo', term_getline(buf, 1))})
+
+  call assert_false(filereadable('Xsig_TERM'))
+
+  " After TSTP the file is not saved (same function as ^Z)
+  exe 'silent !kill -s TSTP ' .. pid_vim
+  call WaitForAssert({-> assert_true(filereadable('.Xsig_TERM.swp'))})
+
+  " We resume after the suspend
+  exe 'silent !kill -s CONT ' .. pid_vim
+  exe 'silent !sleep 0.006'
+
+  call StopVimInTerminal(buf)
+
+  let result = readfile('XautoOut')
+  call assert_equal(["VimSuspend triggered", "VimResume triggered"], result)
+
+  %bwipe!
+  call delete('.Xsig_TERM.swp')
+  call delete('XsetupAucmd')
+  call delete('XautoOut')
+endfunc
+
 " Test a deadly signal.
 "
 " There are several deadly signals: SISEGV, SIBUS, SIGTERM...
index ee3a29f51476a60cceadb10bbc006ac00c156961..2a5260a04216c6b6476b1cfa37075886b8f03f52 100644 (file)
@@ -749,6 +749,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    3941,
 /**/
     3940,
 /**/