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
This commit is contained in:
Kovid Goyal 2018-08-04 09:19:11 +05:30
parent ab7f3310c4
commit 28447d3389
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C

View File

@ -11,6 +11,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
#include <signal.h>
static inline char** static inline char**
serialize_string_tuple(PyObject *src) { 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* static PyObject*
spawn(PyObject *self UNUSED, PyObject *args) { spawn(PyObject *self UNUSED, PyObject *args) {
PyObject *argv_p, *env_p; PyObject *argv_p, *env_p;
@ -55,7 +81,6 @@ spawn(PyObject *self UNUSED, PyObject *args) {
char **argv = serialize_string_tuple(argv_p); char **argv = serialize_string_tuple(argv_p);
char **env = serialize_string_tuple(env_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(); pid_t pid = fork();
switch(pid) { switch(pid) {
case 0: case 0:
@ -63,6 +88,20 @@ spawn(PyObject *self UNUSED, PyObject *args) {
// Use only signal-safe functions (man 7 signal-safety) // Use only signal-safe functions (man 7 signal-safety)
if (chdir(cwd) != 0) { if (chdir("/") != 0) {} }; // ignore failure to chdir to / if (chdir(cwd) != 0) { if (chdir("/") != 0) {} }; // ignore failure to chdir to /
if (setsid() == -1) exit_on_err("setsid() in child process failed"); 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, 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 (dup2(slave, 2) == -1) exit_on_err("dup2() failed for fd number 2");
if (stdin_read_fd > -1) { if (stdin_read_fd > -1) {
@ -76,15 +115,6 @@ spawn(PyObject *self UNUSED, PyObject *args) {
close(master); close(master);
for (int c = 3; c < 201; c++) close(c); 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; environ = env;
execvp(exe, argv); execvp(exe, argv);
// Report the failure and exec a shell instead, so that we are not left // Report the failure and exec a shell instead, so that we are not left