mirror of
https://github.com/vim/vim.git
synced 2025-09-24 03:44:06 -04:00
patch 8.2.3941: SIGTSTP is not handled
Problem: SIGTSTP is not handled. Solution: Handle SIGTSTP like pressing CTRL-Z. (closes #9422)
This commit is contained in:
committed by
Bram Moolenaar
parent
94fb8274ca
commit
ab16ad33ba
@@ -1279,8 +1279,8 @@ VimResume When the Vim instance is resumed after being
|
|||||||
:autocmd VimResume * checktime
|
:autocmd VimResume * checktime
|
||||||
< *VimSuspend*
|
< *VimSuspend*
|
||||||
VimSuspend When the Vim instance is suspended. Only when
|
VimSuspend When the Vim instance is suspended. Only when
|
||||||
CTRL-Z was typed inside Vim, not when the
|
CTRL-Z was typed inside Vim, or when the SIGTSTP
|
||||||
SIGSTOP or SIGTSTP signal was sent to Vim.
|
signal was sent to Vim, but not for SIGSTOP.
|
||||||
*WinClosed*
|
*WinClosed*
|
||||||
WinClosed After closing a window. The pattern is
|
WinClosed After closing a window. The pattern is
|
||||||
matched against the |window-ID|. Both
|
matched against the |window-ID|. Both
|
||||||
|
@@ -109,7 +109,6 @@ static void ex_pedit(exarg_T *eap);
|
|||||||
# define ex_pedit ex_ni
|
# define ex_pedit ex_ni
|
||||||
#endif
|
#endif
|
||||||
static void ex_hide(exarg_T *eap);
|
static void ex_hide(exarg_T *eap);
|
||||||
static void ex_stop(exarg_T *eap);
|
|
||||||
static void ex_exit(exarg_T *eap);
|
static void ex_exit(exarg_T *eap);
|
||||||
static void ex_print(exarg_T *eap);
|
static void ex_print(exarg_T *eap);
|
||||||
#ifdef FEAT_BYTEOFF
|
#ifdef FEAT_BYTEOFF
|
||||||
@@ -6200,7 +6199,7 @@ ex_hide(exarg_T *eap UNUSED)
|
|||||||
/*
|
/*
|
||||||
* ":stop" and ":suspend": Suspend Vim.
|
* ":stop" and ":suspend": Suspend Vim.
|
||||||
*/
|
*/
|
||||||
static void
|
void
|
||||||
ex_stop(exarg_T *eap)
|
ex_stop(exarg_T *eap)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@@ -157,6 +157,11 @@ static void handle_resize(void);
|
|||||||
#if defined(SIGWINCH)
|
#if defined(SIGWINCH)
|
||||||
static RETSIGTYPE sig_winch SIGPROTOARG;
|
static RETSIGTYPE sig_winch SIGPROTOARG;
|
||||||
#endif
|
#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)
|
#if defined(SIGINT)
|
||||||
static RETSIGTYPE catch_sigint SIGPROTOARG;
|
static RETSIGTYPE catch_sigint SIGPROTOARG;
|
||||||
#endif
|
#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().
|
// volatile because it is used in signal handler sig_winch().
|
||||||
static volatile sig_atomic_t do_resize = FALSE;
|
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 char_u *extra_shell_arg = NULL;
|
||||||
static int show_shell_mess = TRUE;
|
static int show_shell_mess = TRUE;
|
||||||
// volatile because it is used in signal handler deathtrap().
|
// volatile because it is used in signal handler deathtrap().
|
||||||
@@ -851,6 +858,24 @@ sig_winch SIGDEFARG(sigarg)
|
|||||||
}
|
}
|
||||||
#endif
|
#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)
|
#if defined(SIGINT)
|
||||||
static RETSIGTYPE
|
static RETSIGTYPE
|
||||||
catch_sigint SIGDEFARG(sigarg)
|
catch_sigint SIGDEFARG(sigarg)
|
||||||
@@ -1158,7 +1183,6 @@ after_sigcont(void)
|
|||||||
|
|
||||||
#if defined(SIGCONT)
|
#if defined(SIGCONT)
|
||||||
static RETSIGTYPE sigcont_handler SIGPROTOARG;
|
static RETSIGTYPE sigcont_handler SIGPROTOARG;
|
||||||
static volatile sig_atomic_t in_mch_suspend = FALSE;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* With multi-threading, suspending might not work immediately. Catch the
|
* With multi-threading, suspending might not work immediately. Catch the
|
||||||
@@ -1353,7 +1377,7 @@ set_signals(void)
|
|||||||
|
|
||||||
#ifdef SIGTSTP
|
#ifdef SIGTSTP
|
||||||
// See mch_init() for the conditions under which we ignore 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
|
#endif
|
||||||
#if defined(SIGCONT)
|
#if defined(SIGCONT)
|
||||||
signal(SIGCONT, sigcont_handler);
|
signal(SIGCONT, sigcont_handler);
|
||||||
@@ -6386,6 +6410,15 @@ select_eintr:
|
|||||||
# ifdef EINTR
|
# ifdef EINTR
|
||||||
if (ret == -1 && errno == 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
|
// Check whether window has been resized, EINTR may be caused by
|
||||||
// SIGWINCH.
|
// SIGWINCH.
|
||||||
if (do_resize)
|
if (do_resize)
|
||||||
@@ -7176,7 +7209,7 @@ gpm_open(void)
|
|||||||
// we are going to suspend or starting an external process
|
// we are going to suspend or starting an external process
|
||||||
// so we shouldn't have problem with this
|
// so we shouldn't have problem with this
|
||||||
# ifdef SIGTSTP
|
# ifdef SIGTSTP
|
||||||
signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
|
signal(SIGTSTP, restricted ? SIG_IGN : (RETSIGTYPE (*)())sig_tstp);
|
||||||
# endif
|
# endif
|
||||||
return 1; // succeed
|
return 1; // succeed
|
||||||
}
|
}
|
||||||
|
@@ -40,6 +40,7 @@ int before_quit_autocmds(win_T *wp, int quit_all, int forceit);
|
|||||||
void ex_quit(exarg_T *eap);
|
void ex_quit(exarg_T *eap);
|
||||||
void tabpage_close(int forceit);
|
void tabpage_close(int forceit);
|
||||||
void tabpage_close_other(tabpage_T *tp, 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_drop(int filec, char_u **filev, int split, void (*callback)(void *), void *cookie);
|
||||||
void handle_any_postponed_drop(void);
|
void handle_any_postponed_drop(void);
|
||||||
void ex_splitview(exarg_T *eap);
|
void ex_splitview(exarg_T *eap);
|
||||||
|
@@ -105,6 +105,58 @@ func Test_signal_INT()
|
|||||||
call StopVimInTerminal(buf)
|
call StopVimInTerminal(buf)
|
||||||
endfunc
|
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.
|
" Test a deadly signal.
|
||||||
"
|
"
|
||||||
" There are several deadly signals: SISEGV, SIBUS, SIGTERM...
|
" There are several deadly signals: SISEGV, SIBUS, SIGTERM...
|
||||||
|
@@ -749,6 +749,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
3941,
|
||||||
/**/
|
/**/
|
||||||
3940,
|
3940,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user