Skip to content

Commit f38eebb

Browse files
GH-97001: Release GIL in termios extension (GH-99503)
Without releasing the GIL calls to termios APIs might block the entire interpreter. (cherry picked from commit 959ba45) Co-authored-by: Ronald Oussoren <[email protected]>
1 parent 85dbd2d commit f38eebb

File tree

2 files changed

+77
-12
lines changed

2 files changed

+77
-12
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Release the GIL when calling termios APIs to avoid blocking threads.

Modules/termios.c

+76-12
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,12 @@ termios_tcgetattr_impl(PyObject *module, int fd)
8282
{
8383
termiosmodulestate *state = PyModule_GetState(module);
8484
struct termios mode;
85-
if (tcgetattr(fd, &mode) == -1) {
85+
int r;
86+
87+
Py_BEGIN_ALLOW_THREADS
88+
r = tcgetattr(fd, &mode);
89+
Py_END_ALLOW_THREADS
90+
if (r == -1) {
8691
return PyErr_SetFromErrno(state->TermiosError);
8792
}
8893

@@ -169,7 +174,12 @@ termios_tcsetattr_impl(PyObject *module, int fd, int when, PyObject *term)
169174
/* Get the old mode, in case there are any hidden fields... */
170175
termiosmodulestate *state = PyModule_GetState(module);
171176
struct termios mode;
172-
if (tcgetattr(fd, &mode) == -1) {
177+
int r;
178+
179+
Py_BEGIN_ALLOW_THREADS
180+
r = tcgetattr(fd, &mode);
181+
Py_END_ALLOW_THREADS
182+
if (r == -1) {
173183
return PyErr_SetFromErrno(state->TermiosError);
174184
}
175185

@@ -211,7 +221,12 @@ termios_tcsetattr_impl(PyObject *module, int fd, int when, PyObject *term)
211221
return PyErr_SetFromErrno(state->TermiosError);
212222
if (cfsetospeed(&mode, (speed_t) ospeed) == -1)
213223
return PyErr_SetFromErrno(state->TermiosError);
214-
if (tcsetattr(fd, when, &mode) == -1)
224+
225+
Py_BEGIN_ALLOW_THREADS
226+
r = tcsetattr(fd, when, &mode);
227+
Py_END_ALLOW_THREADS
228+
229+
if (r == -1)
215230
return PyErr_SetFromErrno(state->TermiosError);
216231

217232
Py_RETURN_NONE;
@@ -235,7 +250,13 @@ termios_tcsendbreak_impl(PyObject *module, int fd, int duration)
235250
/*[clinic end generated code: output=5945f589b5d3ac66 input=dc2f32417691f8ed]*/
236251
{
237252
termiosmodulestate *state = PyModule_GetState(module);
238-
if (tcsendbreak(fd, duration) == -1) {
253+
int r;
254+
255+
Py_BEGIN_ALLOW_THREADS
256+
r = tcsendbreak(fd, duration);
257+
Py_END_ALLOW_THREADS
258+
259+
if (r == -1) {
239260
return PyErr_SetFromErrno(state->TermiosError);
240261
}
241262

@@ -256,7 +277,13 @@ termios_tcdrain_impl(PyObject *module, int fd)
256277
/*[clinic end generated code: output=5fd86944c6255955 input=c99241b140b32447]*/
257278
{
258279
termiosmodulestate *state = PyModule_GetState(module);
259-
if (tcdrain(fd) == -1) {
280+
int r;
281+
282+
Py_BEGIN_ALLOW_THREADS
283+
r = tcdrain(fd);
284+
Py_END_ALLOW_THREADS
285+
286+
if (r == -1) {
260287
return PyErr_SetFromErrno(state->TermiosError);
261288
}
262289

@@ -282,7 +309,13 @@ termios_tcflush_impl(PyObject *module, int fd, int queue)
282309
/*[clinic end generated code: output=2424f80312ec2f21 input=0f7d08122ddc07b5]*/
283310
{
284311
termiosmodulestate *state = PyModule_GetState(module);
285-
if (tcflush(fd, queue) == -1) {
312+
int r;
313+
314+
Py_BEGIN_ALLOW_THREADS
315+
r = tcflush(fd, queue);
316+
Py_END_ALLOW_THREADS
317+
318+
if (r == -1) {
286319
return PyErr_SetFromErrno(state->TermiosError);
287320
}
288321

@@ -308,7 +341,13 @@ termios_tcflow_impl(PyObject *module, int fd, int action)
308341
/*[clinic end generated code: output=afd10928e6ea66eb input=c6aff0640b6efd9c]*/
309342
{
310343
termiosmodulestate *state = PyModule_GetState(module);
311-
if (tcflow(fd, action) == -1) {
344+
int r;
345+
346+
Py_BEGIN_ALLOW_THREADS
347+
r = tcflow(fd, action);
348+
Py_END_ALLOW_THREADS
349+
350+
if (r == -1) {
312351
return PyErr_SetFromErrno(state->TermiosError);
313352
}
314353

@@ -333,7 +372,13 @@ termios_tcgetwinsize_impl(PyObject *module, int fd)
333372
#if defined(TIOCGWINSZ)
334373
termiosmodulestate *state = PyModule_GetState(module);
335374
struct winsize w;
336-
if (ioctl(fd, TIOCGWINSZ, &w) == -1) {
375+
int r;
376+
377+
Py_BEGIN_ALLOW_THREADS
378+
r = ioctl(fd, TIOCGWINSZ, &w);
379+
Py_END_ALLOW_THREADS
380+
381+
if (r == -1) {
337382
return PyErr_SetFromErrno(state->TermiosError);
338383
}
339384

@@ -352,7 +397,12 @@ termios_tcgetwinsize_impl(PyObject *module, int fd)
352397
#elif defined(TIOCGSIZE)
353398
termiosmodulestate *state = PyModule_GetState(module);
354399
struct ttysize s;
355-
if (ioctl(fd, TIOCGSIZE, &s) == -1) {
400+
int r;
401+
402+
Py_BEGIN_ALLOW_THREADS
403+
r = ioctl(fd, TIOCGSIZE, &s);
404+
Py_END_ALLOW_THREADS
405+
if (r == -1) {
356406
return PyErr_SetFromErrno(state->TermiosError);
357407
}
358408

@@ -433,15 +483,25 @@ termios_tcsetwinsize_impl(PyObject *module, int fd, PyObject *winsz)
433483
return NULL;
434484
}
435485

436-
if (ioctl(fd, TIOCSWINSZ, &w) == -1) {
486+
int r;
487+
Py_BEGIN_ALLOW_THREADS
488+
r = ioctl(fd, TIOCSWINSZ, &w);
489+
Py_END_ALLOW_THREADS
490+
491+
if (r == -1) {
437492
return PyErr_SetFromErrno(state->TermiosError);
438493
}
439494

440495
Py_RETURN_NONE;
441496
#elif defined(TIOCGSIZE) && defined(TIOCSSIZE)
442497
struct ttysize s;
498+
int r;
443499
/* Get the old ttysize because it might have more fields. */
444-
if (ioctl(fd, TIOCGSIZE, &s) == -1) {
500+
Py_BEGIN_ALLOW_THREADS
501+
r = ioctl(fd, TIOCGSIZE, &s);
502+
Py_END_ALLOW_THREADS
503+
504+
if (r == -1) {
445505
return PyErr_SetFromErrno(state->TermiosError);
446506
}
447507

@@ -453,7 +513,11 @@ termios_tcsetwinsize_impl(PyObject *module, int fd, PyObject *winsz)
453513
return NULL;
454514
}
455515

456-
if (ioctl(fd, TIOCSSIZE, &s) == -1) {
516+
Py_BEGIN_ALLOW_THREADS
517+
r = ioctl(fd, TIOCSSIZE, &s);
518+
Py_END_ALLOW_THREADS
519+
520+
if (r == -1) {
457521
return PyErr_SetFromErrno(state->TermiosError);
458522
}
459523

0 commit comments

Comments
 (0)