Perform proper cleanup for signals with 'Term' action (#3057)
Issue #3049 describes a case where terminating i3 by means of SIGTERM causes it to leak the runtime directory and all its contents. There are multiple issues at play: first, any cleanup handlers registered via atexit are never invoked when a signal terminates the program (see atexit(3)). Hence, the log SHM log cleanup performed in i3_exit is not invoked in that case. Second, compared to the shutdown path for the 'exit' command, we do not unlink the UNIX domain socket we create, causing it to be leaked as well. Third, a handler for SIGTERM is not registered at all despite handle_signal claiming to be the handler for all 'Term' signals. This change addresses all three problems and results in a graceful exit including cleanup to happen when we receive a signal with the default action 'Term'. It addresses issue #3049.
This commit is contained in:
committed by
Michael Stapelberg
parent
e4d6458cc3
commit
3e34122de4
@ -12,6 +12,7 @@ use AnyEvent::I3;
|
||||
use List::Util qw(first);
|
||||
use Time::HiRes qw(sleep);
|
||||
use Cwd qw(abs_path);
|
||||
use POSIX ':sys_wait_h';
|
||||
use Scalar::Util qw(blessed);
|
||||
use SocketActivation;
|
||||
use i3test::Util qw(slurp);
|
||||
@ -37,6 +38,7 @@ our @EXPORT = qw(
|
||||
cmd
|
||||
sync_with_i3
|
||||
exit_gracefully
|
||||
exit_forcefully
|
||||
workspace_exists
|
||||
focused_ws
|
||||
get_socket_path
|
||||
@ -123,7 +125,7 @@ END {
|
||||
|
||||
} else {
|
||||
kill(-9, $i3_pid)
|
||||
or $tester->BAIL_OUT("could not kill i3");
|
||||
or $tester->BAIL_OUT("could not kill i3: $!");
|
||||
|
||||
waitpid $i3_pid, 0;
|
||||
}
|
||||
@ -759,7 +761,7 @@ sub exit_gracefully {
|
||||
|
||||
if (!$exited) {
|
||||
kill(9, $pid)
|
||||
or $tester->BAIL_OUT("could not kill i3");
|
||||
or $tester->BAIL_OUT("could not kill i3: $!");
|
||||
}
|
||||
|
||||
if ($socketpath =~ m,^/tmp/i3-test-socket-,) {
|
||||
@ -770,6 +772,47 @@ sub exit_gracefully {
|
||||
undef $i3_pid;
|
||||
}
|
||||
|
||||
=head2 exit_forcefully($pid, [ $signal ])
|
||||
|
||||
Tries to exit i3 forcefully by sending a signal (defaults to SIGTERM).
|
||||
|
||||
You only need to use this function if you want to test signal handling
|
||||
(in which case you must have launched i3 on your own with
|
||||
C<launch_with_config>).
|
||||
|
||||
use i3test i3_autostart => 0;
|
||||
my $pid = launch_with_config($config);
|
||||
# …
|
||||
exit_forcefully($pid);
|
||||
|
||||
=cut
|
||||
sub exit_forcefully {
|
||||
my ($pid, $signal) = @_;
|
||||
$signal ||= 'TERM';
|
||||
|
||||
# Send the given signal to the i3 instance and wait for up to 10s
|
||||
# for it to terminate.
|
||||
kill($signal, $pid)
|
||||
or $tester->BAIL_OUT("could not kill i3: $!");
|
||||
my $status;
|
||||
my $timeout = 10;
|
||||
do {
|
||||
$status = waitpid $pid, WNOHANG;
|
||||
|
||||
if ($status <= 0) {
|
||||
sleep(1);
|
||||
$timeout--;
|
||||
}
|
||||
} while ($status <= 0 && $timeout > 0);
|
||||
|
||||
if ($status <= 0) {
|
||||
kill('KILL', $pid)
|
||||
or $tester->BAIL_OUT("could not kill i3: $!");
|
||||
waitpid $pid, 0;
|
||||
}
|
||||
undef $i3_pid;
|
||||
}
|
||||
|
||||
=head2 get_socket_path([ $cache ])
|
||||
|
||||
Gets the socket path from the C<I3_SOCKET_PATH> atom stored on the X11 root
|
||||
|
35
testcases/t/540-sigterm-cleanup.t
Normal file
35
testcases/t/540-sigterm-cleanup.t
Normal file
@ -0,0 +1,35 @@
|
||||
#!perl
|
||||
# vim:ts=4:sw=4:expandtab
|
||||
#
|
||||
# Please read the following documents before working on tests:
|
||||
# • https://build.i3wm.org/docs/testsuite.html
|
||||
# (or docs/testsuite)
|
||||
#
|
||||
# • https://build.i3wm.org/docs/lib-i3test.html
|
||||
# (alternatively: perldoc ./testcases/lib/i3test.pm)
|
||||
#
|
||||
# • https://build.i3wm.org/docs/ipc.html
|
||||
# (or docs/ipc)
|
||||
#
|
||||
# • http://onyxneon.com/books/modern_perl/modern_perl_a4.pdf
|
||||
# (unless you are already familiar with Perl)
|
||||
#
|
||||
# Tests that the socket file is cleaned up properly after gracefully
|
||||
# shutting down i3 via SIGTERM.
|
||||
# Ticket: #3049
|
||||
use i3test i3_autostart => 0;
|
||||
|
||||
my $config = <<EOT;
|
||||
# i3 config file (v4)
|
||||
font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
|
||||
EOT
|
||||
|
||||
my $pid = launch_with_config($config, dont_add_socket_path => 1);
|
||||
my $socket = get_socket_path();
|
||||
ok(-S $socket, "socket $socket exists");
|
||||
|
||||
exit_forcefully($pid, 'TERM');
|
||||
|
||||
ok(!-e $socket, "socket $socket no longer exists");
|
||||
|
||||
done_testing;
|
Reference in New Issue
Block a user