From 28447d33892aa0cef1b22afb232245c023c7dd01 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 4 Aug 2018 09:19:11 +0530 Subject: [PATCH] Only launch child processes after window size is available in the termios structure The delay is minimal ~ 1ms and there are apparently some applications such as kakoune that rely on the window size being available on startup. Since kitty always sizes windows with some size on startup, we can afford to wait. Fixes #786 --- kitty/child.c | 50 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/kitty/child.c b/kitty/child.c index bb2f63a07..88366bc98 100644 --- a/kitty/child.c +++ b/kitty/child.c @@ -11,6 +11,7 @@ #include #include #include +#include static inline char** serialize_string_tuple(PyObject *src) { @@ -44,6 +45,31 @@ write_to_stderr(const char *text) { } } +#define exit_on_err(m) { write_to_stderr(m); write_to_stderr(": "); write_to_stderr(strerror(errno)); exit(EXIT_FAILURE); } + +static sig_atomic_t sigwinch_arrived; + +void handle_sigwinch(int signal) { + if (signal == SIGWINCH) sigwinch_arrived = 1; +} + +static inline void +wait_for_sigwinch() { + sigwinch_arrived = 0; + sigset_t mask, oldmask; + struct sigaction sa; + sa.sa_handler = handle_sigwinch; + sa.sa_flags = SA_RESTART; + if (sigaction(SIGWINCH, &sa, NULL) == -1) { + exit_on_err("Failed to set the SIGWINCH signal handler"); + } + sigemptyset(&mask); + sigaddset(&mask, SIGWINCH); + sigprocmask(SIG_BLOCK, &mask, &oldmask); + while(!sigwinch_arrived) sigsuspend(&oldmask); + sigprocmask(SIG_UNBLOCK, &mask, NULL); +} + static PyObject* spawn(PyObject *self UNUSED, PyObject *args) { PyObject *argv_p, *env_p; @@ -55,7 +81,6 @@ spawn(PyObject *self UNUSED, PyObject *args) { char **argv = serialize_string_tuple(argv_p); char **env = serialize_string_tuple(env_p); -#define exit_on_err(m) { write_to_stderr(m); write_to_stderr(": "); write_to_stderr(strerror(errno)); exit(EXIT_FAILURE); } pid_t pid = fork(); switch(pid) { case 0: @@ -63,6 +88,20 @@ spawn(PyObject *self UNUSED, PyObject *args) { // Use only signal-safe functions (man 7 signal-safety) if (chdir(cwd) != 0) { if (chdir("/") != 0) {} }; // ignore failure to chdir to / if (setsid() == -1) exit_on_err("setsid() in child process failed"); + + // Establish the controlling terminal (see man 7 credentials) + int tfd = open(name, O_RDWR); + if (tfd == -1) exit_on_err("Failed to open controlling terminal"); +#ifdef TIOCSTTY + // On BSD open() does not establish the controlling terminal + if (ioctl(tfd, TIOCSCTTY, 0) == -1) exit_on_err("Failed to set controlling terminal with TIOCSCTTY"); +#endif + close(tfd); + + // Wait for SIGWINCH which indicates kitty has setup the screen object + wait_for_sigwinch(); + + // Redirect stdin/stdout/stderr to the pty if (dup2(slave, 1) == -1) exit_on_err("dup2() failed for fd number 1"); if (dup2(slave, 2) == -1) exit_on_err("dup2() failed for fd number 2"); if (stdin_read_fd > -1) { @@ -76,15 +115,6 @@ spawn(PyObject *self UNUSED, PyObject *args) { close(master); for (int c = 3; c < 201; c++) close(c); - // Establish the controlling terminal (see man 7 credentials) - int tfd = open(name, O_RDWR); - if (tfd == -1) exit_on_err("Failed to open controlling terminal"); -#ifdef TIOCSTTY - // On BSD open() does not establish the controlling terminal - if (ioctl(tfd, TIOCSCTTY, 0) == -1) exit_on_err("Failed to set controlling terminal with TIOCSCTTY"); -#endif - close(tfd); - environ = env; execvp(exe, argv); // Report the failure and exec a shell instead, so that we are not left