No need to use select() for TTYIO
Instead make read() block with timeout via termios
This commit is contained in:
parent
f820f72768
commit
c5583d380d
@ -105,21 +105,29 @@ stop_profiler(PyObject UNUSED *self) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
put_tty_in_raw_mode(int fd, const struct termios* termios_p) {
|
put_tty_in_raw_mode(int fd, const struct termios* termios_p, bool read_with_timeout) {
|
||||||
struct termios raw_termios = *termios_p;
|
struct termios raw_termios = *termios_p;
|
||||||
cfmakeraw(&raw_termios);
|
cfmakeraw(&raw_termios);
|
||||||
|
if (read_with_timeout) {
|
||||||
|
raw_termios.c_cc[VMIN] = 0; raw_termios.c_cc[VTIME] = 1;
|
||||||
|
} else {
|
||||||
raw_termios.c_cc[VMIN] = 1; raw_termios.c_cc[VTIME] = 0;
|
raw_termios.c_cc[VMIN] = 1; raw_termios.c_cc[VTIME] = 0;
|
||||||
|
}
|
||||||
if (tcsetattr(fd, TCSAFLUSH, &raw_termios) != 0) { PyErr_SetFromErrno(PyExc_OSError); return false; }
|
if (tcsetattr(fd, TCSAFLUSH, &raw_termios) != 0) { PyErr_SetFromErrno(PyExc_OSError); return false; }
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
open_tty(PyObject *self UNUSED, PyObject *args UNUSED) {
|
open_tty(PyObject *self UNUSED, PyObject *args) {
|
||||||
int fd = open("/dev/tty", O_RDWR | O_NONBLOCK | O_CLOEXEC | O_NOCTTY);
|
int read_with_timeout = 0;
|
||||||
|
if (!PyArg_ParseTuple(args, "|p", &read_with_timeout)) return NULL;
|
||||||
|
int flags = O_RDWR | O_CLOEXEC | O_NOCTTY;
|
||||||
|
if (!read_with_timeout) flags |= O_NONBLOCK;
|
||||||
|
int fd = open("/dev/tty", flags);
|
||||||
struct termios *termios_p = calloc(1, sizeof(struct termios));
|
struct termios *termios_p = calloc(1, sizeof(struct termios));
|
||||||
if (!termios_p) return PyErr_NoMemory();
|
if (!termios_p) return PyErr_NoMemory();
|
||||||
if (tcgetattr(fd, termios_p) != 0) { free(termios_p); PyErr_SetFromErrno(PyExc_OSError); return NULL; }
|
if (tcgetattr(fd, termios_p) != 0) { free(termios_p); PyErr_SetFromErrno(PyExc_OSError); return NULL; }
|
||||||
if (!put_tty_in_raw_mode(fd, termios_p)) { free(termios_p); return NULL; }
|
if (!put_tty_in_raw_mode(fd, termios_p, read_with_timeout != 0)) { free(termios_p); return NULL; }
|
||||||
return Py_BuildValue("iN", fd, PyLong_FromVoidPtr(termios_p));
|
return Py_BuildValue("iN", fd, PyLong_FromVoidPtr(termios_p));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,7 +146,7 @@ normal_tty(PyObject *self UNUSED, PyObject *args) {
|
|||||||
static PyObject*
|
static PyObject*
|
||||||
raw_tty(PyObject *self UNUSED, PyObject *args) {
|
raw_tty(PyObject *self UNUSED, PyObject *args) {
|
||||||
TTY_ARGS
|
TTY_ARGS
|
||||||
if (!put_tty_in_raw_mode(fd, termios_p)) return NULL;
|
if (!put_tty_in_raw_mode(fd, termios_p, false)) return NULL;
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,7 +163,7 @@ close_tty(PyObject *self UNUSED, PyObject *args) {
|
|||||||
#undef TTY_ARGS
|
#undef TTY_ARGS
|
||||||
|
|
||||||
static PyMethodDef module_methods[] = {
|
static PyMethodDef module_methods[] = {
|
||||||
{"open_tty", open_tty, METH_NOARGS, ""},
|
{"open_tty", open_tty, METH_VARARGS, ""},
|
||||||
{"normal_tty", normal_tty, METH_VARARGS, ""},
|
{"normal_tty", normal_tty, METH_VARARGS, ""},
|
||||||
{"raw_tty", raw_tty, METH_VARARGS, ""},
|
{"raw_tty", raw_tty, METH_VARARGS, ""},
|
||||||
{"close_tty", close_tty, METH_VARARGS, ""},
|
{"close_tty", close_tty, METH_VARARGS, ""},
|
||||||
|
|||||||
@ -369,7 +369,7 @@ def write_all(fd, data):
|
|||||||
class TTYIO:
|
class TTYIO:
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
self.tty_fd, self.original_termios = open_tty()
|
self.tty_fd, self.original_termios = open_tty(True)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __exit__(self, *a):
|
def __exit__(self, *a):
|
||||||
@ -383,17 +383,13 @@ class TTYIO:
|
|||||||
write_all(self.tty_fd, chunk)
|
write_all(self.tty_fd, chunk)
|
||||||
|
|
||||||
def recv(self, more_needed, timeout, sz=1):
|
def recv(self, more_needed, timeout, sz=1):
|
||||||
import select
|
|
||||||
fd = self.tty_fd
|
fd = self.tty_fd
|
||||||
start_time = monotonic()
|
start_time = monotonic()
|
||||||
while timeout > monotonic() - start_time:
|
while timeout > monotonic() - start_time:
|
||||||
rd = select.select([fd], [], [], max(0, timeout - (monotonic() - start_time)))[0]
|
# will block for 0.1 secs waiting for data because we have set
|
||||||
if not rd:
|
# VMIN=0 VTIME=1 in termios
|
||||||
break
|
|
||||||
data = os.read(fd, sz)
|
data = os.read(fd, sz)
|
||||||
if not data:
|
if data and not more_needed(data):
|
||||||
break # eof
|
|
||||||
if not more_needed(data):
|
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user