Dont actually need a thread for PTY

This commit is contained in:
Kovid Goyal 2022-02-24 10:05:13 +05:30
parent 0a297f4656
commit b212fd5bcd
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C

View File

@ -4,13 +4,11 @@
import fcntl import fcntl
import io import io
import os import os
import queue
import select import select
import shlex import shlex
import struct import struct
import sys import sys
import termios import termios
import threading
import time import time
from pty import CHILD, fork from pty import CHILD, fork
from unittest import TestCase from unittest import TestCase
@ -22,7 +20,7 @@ from kitty.fast_data_types import (
from kitty.options.parse import merge_result_dicts from kitty.options.parse import merge_result_dicts
from kitty.options.types import Options, defaults from kitty.options.types import Options, defaults
from kitty.types import MouseEvent from kitty.types import MouseEvent
from kitty.utils import read_screen_size, write_all from kitty.utils import read_screen_size
from kitty.window import process_remote_print from kitty.window import process_remote_print
@ -168,6 +166,7 @@ class PTY:
argv = shlex.split(argv) argv = shlex.split(argv)
pid, self.master_fd = fork() pid, self.master_fd = fork()
self.is_child = pid == CHILD self.is_child = pid == CHILD
self.write_buf = b''
if self.is_child: if self.is_child:
while read_screen_size().width != columns * cell_width: while read_screen_size().width != columns * cell_width:
time.sleep(0.01) time.sleep(0.01)
@ -181,43 +180,36 @@ class PTY:
self.callbacks = Callbacks() self.callbacks = Callbacks()
self.screen = Screen(self.callbacks, rows, columns, scrollback, cell_width, cell_height, 0, self.callbacks) self.screen = Screen(self.callbacks, rows, columns, scrollback, cell_width, cell_height, 0, self.callbacks)
self.received_bytes = b'' self.received_bytes = b''
self.queue = queue.Queue()
self.thread = threading.Thread(name='PTYWriter', target=self.write_loop, daemon=True)
self.thread.start()
def __del__(self): def __del__(self):
if not self.is_child: if not self.is_child:
self.queue.put(None)
fd = self.master_fd fd = self.master_fd
del self.master_fd del self.master_fd
os.close(fd) os.close(fd)
def write_loop(self):
while True:
x = self.queue.get()
if x is None:
break
try:
write_all(self.master_fd, x)
except AttributeError:
break
except OSError as err:
print(f'Failed to write to master_fd: {err}', file=sys.stderr)
def write_to_child(self, data): def write_to_child(self, data):
self.queue.put(data) if isinstance(data, str):
data = data.encode('utf-8')
def wait_for_input_from_child(self, timeout=10): self.write_buf += data
rd = select.select([self.master_fd], [], [], timeout)[0]
return bool(rd)
def send_cmd_to_child(self, cmd): def send_cmd_to_child(self, cmd):
self.write_to_child(cmd + '\r') self.write_to_child(cmd + '\r')
def process_input_from_child(self, timeout=10): def process_input_from_child(self, timeout=10):
self.wait_for_input_from_child(timeout=10) rd, wd, err = select.select([self.master_fd], [self.master_fd] if self.write_buf else [], [self.master_fd], timeout)
if err:
raise OSError('master_fd is in error condition')
while wd:
try:
n = os.write(self.master_fd, self.write_buf)
except (BlockingIOError, OSError):
n = 0
if not n:
break
self.write_buf = self.write_buf[n:]
bytes_read = 0 bytes_read = 0
while True: while rd:
try: try:
data = os.read(self.master_fd, io.DEFAULT_BUFFER_SIZE) data = os.read(self.master_fd, io.DEFAULT_BUFFER_SIZE)
except (BlockingIOError, OSError): except (BlockingIOError, OSError):