Fix regression in 0.26.0 that caused launching kitty without working STDIO handles to result in high CPU usage and prewarming failing
Fixes #5444
This commit is contained in:
@@ -40,6 +40,8 @@ Detailed list of changes
|
|||||||
|
|
||||||
- hyperlinked_grep kitten: Allow control which parts of rg output are hyperlinked (:pull:`5428`)
|
- hyperlinked_grep kitten: Allow control which parts of rg output are hyperlinked (:pull:`5428`)
|
||||||
|
|
||||||
|
- Fix regression in 0.26.0 that caused launching kitty without working STDIO handles to result in high CPU usage and prewarming failing (:iss:`5444`)
|
||||||
|
|
||||||
0.26.1 [2022-08-30]
|
0.26.1 [2022-08-30]
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
#ifndef KITTY_LIB_PATH
|
#ifndef KITTY_LIB_PATH
|
||||||
#define KITTY_LIB_PATH "../.."
|
#define KITTY_LIB_PATH "../.."
|
||||||
@@ -268,9 +269,55 @@ read_exe_path(char *exe, size_t buf_sz) {
|
|||||||
}
|
}
|
||||||
#endif // }}}
|
#endif // }}}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
is_valid_fd(int fd)
|
||||||
|
{
|
||||||
|
// This is copied from the python source code as we need the exact same semantics
|
||||||
|
// to prevent python from giving us None for sys.stdout and friends.
|
||||||
|
#if defined(F_GETFD) && ( \
|
||||||
|
defined(__linux__) || \
|
||||||
|
defined(__APPLE__) || \
|
||||||
|
defined(__wasm__))
|
||||||
|
return fcntl(fd, F_GETFD) >= 0;
|
||||||
|
#elif defined(__linux__)
|
||||||
|
int fd2 = dup(fd);
|
||||||
|
if (fd2 >= 0) {
|
||||||
|
close(fd2);
|
||||||
|
}
|
||||||
|
return (fd2 >= 0);
|
||||||
|
#else
|
||||||
|
struct stat st;
|
||||||
|
return (fstat(fd, &st) == 0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
reopen_to_null(const char *mode, FILE *stream) {
|
||||||
|
errno = 0;
|
||||||
|
while (true) {
|
||||||
|
if (freopen("/dev/null", mode, stream) != NULL) return true;
|
||||||
|
if (errno == EINTR) continue;
|
||||||
|
perror("Failed to re-open STDIO handle to /dev/null");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
ensure_working_stdio(void) {
|
||||||
|
#define C(which, mode) { \
|
||||||
|
int fd = fileno(which); \
|
||||||
|
if (fd < 0) { if (!reopen_to_null(mode, which)) return false; } \
|
||||||
|
else if (!is_valid_fd(fd)) { \
|
||||||
|
close(fd); if (!reopen_to_null(mode, which)) return false; \
|
||||||
|
}}
|
||||||
|
C(stdin, "r") C(stdout, "w") C(stderr, "w")
|
||||||
|
return true;
|
||||||
|
#undef C
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[], char* envp[]) {
|
int main(int argc, char *argv[], char* envp[]) {
|
||||||
if (argc < 1 || !argv) { fprintf(stderr, "Invalid argc/argv\n"); return 1; }
|
if (argc < 1 || !argv) { fprintf(stderr, "Invalid argc/argv\n"); return 1; }
|
||||||
|
if (!ensure_working_stdio()) return 1;
|
||||||
char exe[PATH_MAX+1] = {0};
|
char exe[PATH_MAX+1] = {0};
|
||||||
char exe_dir_buf[PATH_MAX+1] = {0};
|
char exe_dir_buf[PATH_MAX+1] = {0};
|
||||||
FREE_AFTER_FUNCTION const char *lc_ctype = NULL;
|
FREE_AFTER_FUNCTION const char *lc_ctype = NULL;
|
||||||
|
|||||||
@@ -107,6 +107,22 @@ class TestBuild(BaseTest):
|
|||||||
run_tests(partial(docs_url, local_docs_root=None), w, '/')
|
run_tests(partial(docs_url, local_docs_root=None), w, '/')
|
||||||
self.ae(docs_url('#ref=issues-123'), 'https://github.com/kovidgoyal/kitty/issues/123')
|
self.ae(docs_url('#ref=issues-123'), 'https://github.com/kovidgoyal/kitty/issues/123')
|
||||||
|
|
||||||
|
def test_launcher_ensures_stdio(self):
|
||||||
|
from kitty.constants import kitty_exe
|
||||||
|
import subprocess
|
||||||
|
exe = kitty_exe()
|
||||||
|
cp = subprocess.run([exe, '+runpy', '''\
|
||||||
|
import os, sys
|
||||||
|
if sys.stdin:
|
||||||
|
os.close(sys.stdin.fileno())
|
||||||
|
if sys.stdout:
|
||||||
|
os.close(sys.stdout.fileno())
|
||||||
|
if sys.stderr:
|
||||||
|
os.close(sys.stderr.fileno())
|
||||||
|
os.execlp('kitty', 'kitty', '+runpy', 'import sys; raise SystemExit(1 if sys.stdout is None or sys.stdin is None or sys.stderr is None else 0)')
|
||||||
|
'''])
|
||||||
|
self.assertEqual(cp.returncode, 0)
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
tests = unittest.defaultTestLoader.loadTestsFromTestCase(TestBuild)
|
tests = unittest.defaultTestLoader.loadTestsFromTestCase(TestBuild)
|
||||||
|
|||||||
Reference in New Issue
Block a user