Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a47fc5c

Browse files
committed
Issue #23694: Handle EINTR in _Py_open() and _Py_fopen_obj()
Retry open()/fopen() if it fails with EINTR and the Python signal handler doesn't raise an exception.
1 parent 9c1a9b2 commit a47fc5c

1 file changed

Lines changed: 40 additions & 13 deletions

File tree

Python/fileutils.c

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -912,6 +912,7 @@ static int
912912
_Py_open_impl(const char *pathname, int flags, int gil_held)
913913
{
914914
int fd;
915+
int async_err = 0;
915916
#ifndef MS_WINDOWS
916917
int *atomic_flag_works;
917918
#endif
@@ -926,10 +927,14 @@ _Py_open_impl(const char *pathname, int flags, int gil_held)
926927
#endif
927928

928929
if (gil_held) {
929-
Py_BEGIN_ALLOW_THREADS
930-
fd = open(pathname, flags);
931-
Py_END_ALLOW_THREADS
932-
930+
do {
931+
Py_BEGIN_ALLOW_THREADS
932+
fd = open(pathname, flags);
933+
Py_END_ALLOW_THREADS
934+
} while (fd < 0
935+
&& errno == EINTR && !(async_err = PyErr_CheckSignals()));
936+
if (async_err)
937+
return -1;
933938
if (fd < 0) {
934939
PyErr_SetFromErrnoWithFilename(PyExc_OSError, pathname);
935940
return -1;
@@ -957,6 +962,9 @@ _Py_open_impl(const char *pathname, int flags, int gil_held)
957962
958963
The file descriptor is created non-inheritable.
959964
965+
When interrupted by a signal (open() fails with EINTR), retry the syscall,
966+
except if the Python signal handler raises an exception.
967+
960968
The GIL must be held. */
961969
int
962970
_Py_open(const char *pathname, int flags)
@@ -969,7 +977,9 @@ _Py_open(const char *pathname, int flags)
969977
/* Open a file with the specified flags (wrapper to open() function).
970978
Return a file descriptor on success. Set errno and return -1 on error.
971979
972-
The file descriptor is created non-inheritable. */
980+
The file descriptor is created non-inheritable.
981+
982+
If interrupted by a signal, fail with EINTR. */
973983
int
974984
_Py_open_noraise(const char *pathname, int flags)
975985
{
@@ -979,7 +989,9 @@ _Py_open_noraise(const char *pathname, int flags)
979989
/* Open a file. Use _wfopen() on Windows, encode the path to the locale
980990
encoding and use fopen() otherwise.
981991
982-
The file descriptor is created non-inheritable). */
992+
The file descriptor is created non-inheritable.
993+
994+
If interrupted by a signal, fail with EINTR. */
983995
FILE *
984996
_Py_wfopen(const wchar_t *path, const wchar_t *mode)
985997
{
@@ -1012,7 +1024,9 @@ _Py_wfopen(const wchar_t *path, const wchar_t *mode)
10121024

10131025
/* Wrapper to fopen().
10141026
1015-
The file descriptor is created non-inheritable). */
1027+
The file descriptor is created non-inheritable.
1028+
1029+
If interrupted by a signal, fail with EINTR. */
10161030
FILE*
10171031
_Py_fopen(const char *pathname, const char *mode)
10181032
{
@@ -1034,11 +1048,15 @@ _Py_fopen(const char *pathname, const char *mode)
10341048
10351049
The file descriptor is created non-inheritable.
10361050
1051+
When interrupted by a signal (open() fails with EINTR), retry the syscall,
1052+
except if the Python signal handler raises an exception.
1053+
10371054
The GIL must be held. */
10381055
FILE*
10391056
_Py_fopen_obj(PyObject *path, const char *mode)
10401057
{
10411058
FILE *f;
1059+
int async_err = 0;
10421060
#ifdef MS_WINDOWS
10431061
wchar_t *wpath;
10441062
wchar_t wmode[10];
@@ -1062,9 +1080,12 @@ _Py_fopen_obj(PyObject *path, const char *mode)
10621080
return NULL;
10631081
}
10641082

1065-
Py_BEGIN_ALLOW_THREADS
1066-
f = _wfopen(wpath, wmode);
1067-
Py_END_ALLOW_THREADS
1083+
do {
1084+
Py_BEGIN_ALLOW_THREADS
1085+
f = _wfopen(wpath, wmode);
1086+
Py_END_ALLOW_THREADS
1087+
} while (f == NULL
1088+
&& errno == EINTR && !(async_err = PyErr_CheckSignals()));
10681089
#else
10691090
PyObject *bytes;
10701091
char *path_bytes;
@@ -1075,12 +1096,18 @@ _Py_fopen_obj(PyObject *path, const char *mode)
10751096
return NULL;
10761097
path_bytes = PyBytes_AS_STRING(bytes);
10771098

1078-
Py_BEGIN_ALLOW_THREADS
1079-
f = fopen(path_bytes, mode);
1080-
Py_END_ALLOW_THREADS
1099+
do {
1100+
Py_BEGIN_ALLOW_THREADS
1101+
f = fopen(path_bytes, mode);
1102+
Py_END_ALLOW_THREADS
1103+
} while (f == NULL
1104+
&& errno == EINTR && !(async_err = PyErr_CheckSignals()));
10811105

10821106
Py_DECREF(bytes);
10831107
#endif
1108+
if (async_err)
1109+
return NULL;
1110+
10841111
if (f == NULL) {
10851112
PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path);
10861113
return NULL;

0 commit comments

Comments
 (0)