Forward termination signals

This commit is contained in:
Kovid Goyal 2022-07-07 08:40:17 +05:30
parent 51698dff07
commit d080bf3b9c
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 41 additions and 2 deletions

View File

@ -28,7 +28,11 @@ class Prewarm(BaseTest):
from kitty.prewarm import fork_prewarm_process, wait_for_child_death
exit_code = 17
src = '''\
def socket_child_main(exit_code=0):
def socket_child_main(exit_code=0, for_signal=False):
if for_signal:
print('child ready')
sys.stdin.read()
raise SystemExit(exit_code)
import json
import os
import sys
@ -84,6 +88,20 @@ def socket_child_main(exit_code=0):
self.assertEqual(output['stdin_data'], stdin_data)
self.assertEqual(stdout_data, 'testing stdout')
stdin_r, stdin_w = os.pipe()
os.set_inheritable(stdin_w, False)
pty = self.create_pty(
argv=[kitty_exe(), '+runpy', src + 'socket_child_main(for_signal=True)'], cols=cols, env=env, cwd=cwd, stdin_fd=stdin_r)
pty.wait_till(lambda: 'child ready' in pty.screen_contents())
os.kill(pty.child_pid, signal.SIGINT)
pty.wait_till(lambda: 'Traceback' in pty.screen_contents())
status = wait_for_child_death(pty.child_pid, timeout=5)
if status is None:
os.kill(pty.child_pid, signal.SIGKILL)
self.assertIsNotNone(status, 'prewarm wrapper process did not exit')
with suppress(AttributeError):
self.assertEqual(os.waitstatus_to_exitcode(status), 128 + signal.SIGINT)
def test_prewarming(self):
from kitty.prewarm import fork_prewarm_process

View File

@ -175,6 +175,7 @@ static pid_t child_pid = 0;
static void
cleanup(void) {
child_pid = 0;
if (self_ttyfd > -1 && termios_needs_restore) { safe_tcsetattr(self_ttyfd, TCSAFLUSH, &restore_termios); termios_needs_restore = false; }
#define cfd(fd) if (fd > -1) { safe_close(fd); fd = -1; }
cfd(child_master_fd); cfd(child_slave_fd);
@ -241,6 +242,9 @@ setup_signal_handler(void) {
set_blocking(signal_read_fd, false); set_blocking(signal_write_fd, false);
struct sigaction act = {.sa_sigaction=handle_signal, .sa_flags=SA_SIGINFO | SA_RESTART};
if (sigaction(SIGWINCH, &act, NULL) != 0) return false;
if (sigaction(SIGINT, &act, NULL) != 0) return false;
if (sigaction(SIGTERM, &act, NULL) != 0) return false;
if (sigaction(SIGHUP, &act, NULL) != 0) return false;
return true;
}
@ -304,6 +308,7 @@ create_launch_msg(int argc, char *argv[]) {
static int exit_status = EXIT_FAILURE;
static char from_child_buf[64] = {0};
static size_t from_child_buf_pos = 0;
static int pending_signals[32] = {0};
static bool
read_child_data(void) {
@ -327,6 +332,10 @@ read_child_data(void) {
memset(from_child_buf, 0, (p - from_child_buf) + 1);
from_child_buf_pos -= (p - from_child_buf) + 1;
if (from_child_buf_pos) memmove(from_child_buf, p + 1, from_child_buf_pos);
for (size_t i = 0; i < arraysz(pending_signals) && pending_signals[i]; i++) {
kill(child_pid, pending_signals[i]);
}
memset(pending_signals, 0, sizeof(pending_signals));
}
}
return true;
@ -416,6 +425,17 @@ read_signals(void) {
switch(sig->si_signo) {
case SIGWINCH:
window_size_dirty = true; break;
case SIGINT: case SIGTERM: case SIGHUP:
if (child_pid > 0) kill(child_pid, sig->si_signo);
else {
for (size_t i = 0; i < arraysz(pending_signals); i++) {
if (!pending_signals[i]) {
pending_signals[i] = sig->si_signo;
break;
}
}
}
break;
}
memmove(buf, buf + sizeof(siginfo_t), sizeof(siginfo_t));
buf_pos -= sizeof(siginfo_t);
@ -480,6 +500,7 @@ loop(void) {
}
if (pd(socket_fd).revents & POLLHUP) {
if (from_child_buf[0]) { parse_int(from_child_buf, &exit_status); }
child_pid = 0;
return;
}
if (pd(socket_fd).revents & POLLOUT) {
@ -518,6 +539,7 @@ use_prewarmed_process(int argc, char *argv[]) {
if (!env_addr) return;
self_ttyfd = safe_open(ctermid(NULL), O_RDWR | O_NONBLOCK, 0);
#define fail(s) { print_error(s, errno); cleanup(); return; }
if (!setup_signal_handler()) fail("Failed to setup signal handling");
if (self_ttyfd == -1) fail("Failed to open controlling terminal");
if (!get_window_size()) fail("Failed to get window size of controlling terminal");
if (!get_termios_state()) fail("Failed to get termios state of controlling terminal");
@ -529,7 +551,6 @@ use_prewarmed_process(int argc, char *argv[]) {
while (tcsetattr(self_ttyfd, TCSANOW, &self_termios) == -1 && errno == EINTR) {}
setup_stdio_handles();
if (!create_launch_msg(argc, argv)) fail("Failed to open controlling terminal");
if (!setup_signal_handler()) fail("Failed to setup signal handling");
socket_fd = connect_to_socket_synchronously(env_addr);
if (socket_fd < 0) fail("Failed to connect to prewarm socket");
from_child_tty.buf = malloc(IO_BUZ_SZ * 2);