A process can block, ignore, or catch signals. You can see how a given process handles signals with this shell command:
$ cat /proc/PID/status | grep -E '^Sig(Blk|Ign|Cgt):'
│ │ │
│ │ └ caught signals
│ └ ignored signals
└ blocked signals
Replace PID
with Vim's pid (process ID).
You'll get some output which could look like this:
SigBlk: 0000000000000000
SigIgn: 0000000000003000
SigCgt: 00000001ef824eff
The numbers on the right are bitmasks written in hexadecimal. To understand their meaning, you must convert them in binary; for example with bc(1)
:
$ echo 'ibase=16;obase=2;ABC123' | bc
101010111100000100100011
The index of each non-zero bit stands for the number of a signal.
So, for example, if you have this bitmask:
SigCgt: 00000000280b2603
It can be converted in binary, and interpreted like so:
SigCgt: 101010111100000100100011
│ │ ││
│ │ │└ the signal 1 is caught (SIGHUP)
│ │ └ the signal 2 is caught (SIGINT)
│ └ the signal 6 is caught (SIGUSR1)
└ ...
Here is a short shell script which I sometimes use while debugging a process:
#!/bin/bash
if [[ $# -eq 0 ]]; then
cat <<EOF >&2
usage:
$0 <pid>
EOF
exit 64
fi
# https://unix.stackexchange.com/a/85365/289772
bitmask2signals() {
i=0
bits="$(printf 'ibase=16; obase=2; %X\n' "0x$1" | bc)"
while [[ -n "${bits}" ]]; do
i=$((i + 1))
if [[ "${bits}" == *1 ]]; then
printf ' %s(%s)' "$(kill -l "$i")" "$i"
fi
bits="${bits%?}"
done
}
grep -E '^Sig(Blk|Ign|Cgt):' "/proc/$1/status" |
while read -r a b; do
printf '%s%s\n' "$a" "$(bitmask2signals "$b")"
done
It's taken and adapted from this unix.stackexchange.com answer. If I pass the pid of a Vim process as an argument to the script, here is its output:
SigBlk:
SigIgn: PIPE(13) ALRM(14)
SigCgt: HUP(1) INT(2) QUIT(3) ILL(4) TRAP(5) ABRT(6) BUS(7) FPE(8) USR1(10) SEGV(11) USR2(12) TERM(15) CONT(18) XCPU(24) XFSZ(25) VTALRM(26) PROF(27) WINCH(28) PWR(30) SYS(31) (32) (33)
Notice that TERM(15)
is on the third line SigCgt
. SIGTERM
is the default signal sent to a process when using kill(1)
on linux. As you can see, Vim catches it.
For a process, catching a signal means that it has registered a handler which will be automatically run whenever
the signal is received. This handler will determine the behavior of the process.
For Vim, I think the handler is defined here. Notice that the comment says that the caught signals are blocked when Vim is busy:
/*
* Handling of SIGHUP, SIGQUIT and SIGTERM:
* "when" == a signal: when busy, postpone and return FALSE, otherwise
* return TRUE
* "when" == SIGNAL_BLOCK: Going to be busy, block signals
* "when" == SIGNAL_UNBLOCK: Going to wait, unblock signals, use postponed
* signal
* Returns TRUE when Vim should exit.
*/
My guess is that when you invoke system()
, Vim is busy waiting for the shell command to finish; so it blocks the signal. This is confirmed by the fact that the issue disappears if you use job_start()
instead:
:call job_start('kill ' . getpid())
Because in that case, Vim doesn't need to wait for the command to finish.
!kill -9 $PPID
works for me (but!kill $PPID
) doesn't, so it's probably about how vim handles signals... But I'm not enough of a linux guru to give more insights :) Alsokill
without-9
works from a term buffer.