bpo-1635741: Port the termios to multi-phase init (PEP 489) (GH-22139)

This commit is contained in:
Mohamed Koubaa 2020-09-08 03:59:15 -05:00 committed by GitHub
parent b0ac5d75a5
commit 15dcdb2113
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 106 additions and 84 deletions

View file

@ -0,0 +1,2 @@
Port the :mod:`termios` extension module to multi-phase initialization
(:pep:`489`).

View file

@ -51,8 +51,6 @@ get_termios_state(PyObject *module)
return (termiosmodulestate *)state; return (termiosmodulestate *)state;
} }
#define modulestate_global get_termios_state(PyState_FindModule(&termiosmodule))
static int fdconv(PyObject* obj, void* p) static int fdconv(PyObject* obj, void* p)
{ {
int fd; int fd;
@ -79,31 +77,32 @@ indexing in the cc array must be done using the symbolic constants defined\n\
in this module."); in this module.");
static PyObject * static PyObject *
termios_tcgetattr(PyObject *self, PyObject *args) termios_tcgetattr(PyObject *module, PyObject *args)
{ {
int fd; int fd;
if (!PyArg_ParseTuple(args, "O&:tcgetattr",
fdconv, (void*)&fd)) {
return NULL;
}
termiosmodulestate *state = PyModule_GetState(module);
struct termios mode; struct termios mode;
PyObject *cc; if (tcgetattr(fd, &mode) == -1) {
speed_t ispeed, ospeed; return PyErr_SetFromErrno(state->TermiosError);
}
speed_t ispeed = cfgetispeed(&mode);
speed_t ospeed = cfgetospeed(&mode);
PyObject *cc = PyList_New(NCCS);
if (cc == NULL) {
return NULL;
}
PyObject *v; PyObject *v;
int i; int i;
char ch;
if (!PyArg_ParseTuple(args, "O&:tcgetattr",
fdconv, (void*)&fd))
return NULL;
if (tcgetattr(fd, &mode) == -1)
return PyErr_SetFromErrno(modulestate_global->TermiosError);
ispeed = cfgetispeed(&mode);
ospeed = cfgetospeed(&mode);
cc = PyList_New(NCCS);
if (cc == NULL)
return NULL;
for (i = 0; i < NCCS; i++) { for (i = 0; i < NCCS; i++) {
ch = (char)mode.c_cc[i]; char ch = (char)mode.c_cc[i];
v = PyBytes_FromStringAndSize(&ch, 1); v = PyBytes_FromStringAndSize(&ch, 1);
if (v == NULL) if (v == NULL)
goto err; goto err;
@ -156,17 +155,15 @@ queued output, or termios.TCSAFLUSH to change after transmitting all\n\
queued output and discarding all queued input. "); queued output and discarding all queued input. ");
static PyObject * static PyObject *
termios_tcsetattr(PyObject *self, PyObject *args) termios_tcsetattr(PyObject *module, PyObject *args)
{ {
int fd, when; int fd, when;
struct termios mode; PyObject *term;
speed_t ispeed, ospeed;
PyObject *term, *cc, *v;
int i;
if (!PyArg_ParseTuple(args, "O&iO:tcsetattr", if (!PyArg_ParseTuple(args, "O&iO:tcsetattr",
fdconv, &fd, &when, &term)) fdconv, &fd, &when, &term)) {
return NULL; return NULL;
}
if (!PyList_Check(term) || PyList_Size(term) != 7) { if (!PyList_Check(term) || PyList_Size(term) != 7) {
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"tcsetattr, arg 3: must be 7 element list"); "tcsetattr, arg 3: must be 7 element list");
@ -174,18 +171,22 @@ termios_tcsetattr(PyObject *self, PyObject *args)
} }
/* Get the old mode, in case there are any hidden fields... */ /* Get the old mode, in case there are any hidden fields... */
termiosmodulestate *state = modulestate_global; termiosmodulestate *state = PyModule_GetState(module);
if (tcgetattr(fd, &mode) == -1) struct termios mode;
if (tcgetattr(fd, &mode) == -1) {
return PyErr_SetFromErrno(state->TermiosError); return PyErr_SetFromErrno(state->TermiosError);
}
mode.c_iflag = (tcflag_t) PyLong_AsLong(PyList_GetItem(term, 0)); mode.c_iflag = (tcflag_t) PyLong_AsLong(PyList_GetItem(term, 0));
mode.c_oflag = (tcflag_t) PyLong_AsLong(PyList_GetItem(term, 1)); mode.c_oflag = (tcflag_t) PyLong_AsLong(PyList_GetItem(term, 1));
mode.c_cflag = (tcflag_t) PyLong_AsLong(PyList_GetItem(term, 2)); mode.c_cflag = (tcflag_t) PyLong_AsLong(PyList_GetItem(term, 2));
mode.c_lflag = (tcflag_t) PyLong_AsLong(PyList_GetItem(term, 3)); mode.c_lflag = (tcflag_t) PyLong_AsLong(PyList_GetItem(term, 3));
ispeed = (speed_t) PyLong_AsLong(PyList_GetItem(term, 4)); speed_t ispeed = (speed_t) PyLong_AsLong(PyList_GetItem(term, 4));
ospeed = (speed_t) PyLong_AsLong(PyList_GetItem(term, 5)); speed_t ospeed = (speed_t) PyLong_AsLong(PyList_GetItem(term, 5));
cc = PyList_GetItem(term, 6); PyObject *cc = PyList_GetItem(term, 6);
if (PyErr_Occurred()) if (PyErr_Occurred()) {
return NULL; return NULL;
}
if (!PyList_Check(cc) || PyList_Size(cc) != NCCS) { if (!PyList_Check(cc) || PyList_Size(cc) != NCCS) {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
@ -194,6 +195,8 @@ termios_tcsetattr(PyObject *self, PyObject *args)
return NULL; return NULL;
} }
int i;
PyObject *v;
for (i = 0; i < NCCS; i++) { for (i = 0; i < NCCS; i++) {
v = PyList_GetItem(cc, i); v = PyList_GetItem(cc, i);
@ -226,15 +229,18 @@ A zero duration sends a break for 0.25-0.5 seconds; a nonzero duration\n\
has a system dependent meaning."); has a system dependent meaning.");
static PyObject * static PyObject *
termios_tcsendbreak(PyObject *self, PyObject *args) termios_tcsendbreak(PyObject *module, PyObject *args)
{ {
int fd, duration; int fd, duration;
if (!PyArg_ParseTuple(args, "O&i:tcsendbreak", if (!PyArg_ParseTuple(args, "O&i:tcsendbreak",
fdconv, &fd, &duration)) fdconv, &fd, &duration)) {
return NULL; return NULL;
if (tcsendbreak(fd, duration) == -1) }
return PyErr_SetFromErrno(modulestate_global->TermiosError);
termiosmodulestate *state = PyModule_GetState(module);
if (tcsendbreak(fd, duration) == -1) {
return PyErr_SetFromErrno(state->TermiosError);
}
Py_RETURN_NONE; Py_RETURN_NONE;
} }
@ -245,15 +251,18 @@ PyDoc_STRVAR(termios_tcdrain__doc__,
Wait until all output written to file descriptor fd has been transmitted."); Wait until all output written to file descriptor fd has been transmitted.");
static PyObject * static PyObject *
termios_tcdrain(PyObject *self, PyObject *args) termios_tcdrain(PyObject *module, PyObject *args)
{ {
int fd; int fd;
if (!PyArg_ParseTuple(args, "O&:tcdrain", if (!PyArg_ParseTuple(args, "O&:tcdrain",
fdconv, &fd)) fdconv, &fd)) {
return NULL; return NULL;
if (tcdrain(fd) == -1) }
return PyErr_SetFromErrno(modulestate_global->TermiosError);
termiosmodulestate *state = PyModule_GetState(module);
if (tcdrain(fd) == -1) {
return PyErr_SetFromErrno(state->TermiosError);
}
Py_RETURN_NONE; Py_RETURN_NONE;
} }
@ -267,15 +276,18 @@ queue, termios.TCOFLUSH for the output queue, or termios.TCIOFLUSH for\n\
both queues. "); both queues. ");
static PyObject * static PyObject *
termios_tcflush(PyObject *self, PyObject *args) termios_tcflush(PyObject *module, PyObject *args)
{ {
int fd, queue; int fd, queue;
if (!PyArg_ParseTuple(args, "O&i:tcflush", if (!PyArg_ParseTuple(args, "O&i:tcflush",
fdconv, &fd, &queue)) fdconv, &fd, &queue)) {
return NULL; return NULL;
if (tcflush(fd, queue) == -1) }
return PyErr_SetFromErrno(modulestate_global->TermiosError);
termiosmodulestate *state = PyModule_GetState(module);
if (tcflush(fd, queue) == -1) {
return PyErr_SetFromErrno(state->TermiosError);
}
Py_RETURN_NONE; Py_RETURN_NONE;
} }
@ -289,15 +301,18 @@ termios.TCOON to restart output, termios.TCIOFF to suspend input,\n\
or termios.TCION to restart input."); or termios.TCION to restart input.");
static PyObject * static PyObject *
termios_tcflow(PyObject *self, PyObject *args) termios_tcflow(PyObject *module, PyObject *args)
{ {
int fd, action; int fd, action;
if (!PyArg_ParseTuple(args, "O&i:tcflow", if (!PyArg_ParseTuple(args, "O&i:tcflow",
fdconv, &fd, &action)) fdconv, &fd, &action)) {
return NULL; return NULL;
if (tcflow(fd, action) == -1) }
return PyErr_SetFromErrno(modulestate_global->TermiosError);
termiosmodulestate *state = PyModule_GetState(module);
if (tcflow(fd, action) == -1) {
return PyErr_SetFromErrno(state->TermiosError);
}
Py_RETURN_NONE; Py_RETURN_NONE;
} }
@ -997,44 +1012,49 @@ static void termiosmodule_free(void *m) {
termiosmodule_clear((PyObject *)m); termiosmodule_clear((PyObject *)m);
} }
static struct PyModuleDef termiosmodule = { static int
PyModuleDef_HEAD_INIT, termios_exec(PyObject *mod)
"termios",
termios__doc__,
sizeof(termiosmodulestate),
termios_methods,
NULL,
termiosmodule_traverse,
termiosmodule_clear,
termiosmodule_free,
};
PyMODINIT_FUNC
PyInit_termios(void)
{ {
PyObject *m;
struct constant *constant = termios_constants; struct constant *constant = termios_constants;
termiosmodulestate *state = get_termios_state(mod);
if ((m = PyState_FindModule(&termiosmodule)) != NULL) {
Py_INCREF(m);
return m;
}
if ((m = PyModule_Create(&termiosmodule)) == NULL) {
return NULL;
}
termiosmodulestate *state = get_termios_state(m);
state->TermiosError = PyErr_NewException("termios.error", NULL, NULL); state->TermiosError = PyErr_NewException("termios.error", NULL, NULL);
if (state->TermiosError == NULL) { if (state->TermiosError == NULL) {
return NULL; return -1;
} }
Py_INCREF(state->TermiosError); Py_INCREF(state->TermiosError);
PyModule_AddObject(m, "error", state->TermiosError); if (PyModule_AddObject(mod, "error", state->TermiosError) < 0) {
Py_DECREF(state->TermiosError);
return -1;
}
while (constant->name != NULL) { while (constant->name != NULL) {
PyModule_AddIntConstant(m, constant->name, constant->value); if (PyModule_AddIntConstant(
mod, constant->name, constant->value) < 0) {
return -1;
}
++constant; ++constant;
} }
return m; return 0;
}
static PyModuleDef_Slot termios_slots[] = {
{Py_mod_exec, termios_exec},
{0, NULL}
};
static struct PyModuleDef termiosmodule = {
PyModuleDef_HEAD_INIT,
.m_name = "termios",
.m_doc = termios__doc__,
.m_size = sizeof(termiosmodulestate),
.m_methods = termios_methods,
.m_slots = termios_slots,
.m_traverse = termiosmodule_traverse,
.m_clear = termiosmodule_clear,
.m_free = termiosmodule_free,
};
PyMODINIT_FUNC PyInit_termios(void)
{
return PyModuleDef_Init(&termiosmodule);
} }