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.
This commit is contained in:
Victor Stinner 2015-03-18 09:52:54 +01:00
parent 9c1a9b2657
commit a47fc5c2dd

View file

@ -912,6 +912,7 @@ static int
_Py_open_impl(const char *pathname, int flags, int gil_held) _Py_open_impl(const char *pathname, int flags, int gil_held)
{ {
int fd; int fd;
int async_err = 0;
#ifndef MS_WINDOWS #ifndef MS_WINDOWS
int *atomic_flag_works; int *atomic_flag_works;
#endif #endif
@ -926,10 +927,14 @@ _Py_open_impl(const char *pathname, int flags, int gil_held)
#endif #endif
if (gil_held) { if (gil_held) {
Py_BEGIN_ALLOW_THREADS do {
fd = open(pathname, flags); Py_BEGIN_ALLOW_THREADS
Py_END_ALLOW_THREADS fd = open(pathname, flags);
Py_END_ALLOW_THREADS
} while (fd < 0
&& errno == EINTR && !(async_err = PyErr_CheckSignals()));
if (async_err)
return -1;
if (fd < 0) { if (fd < 0) {
PyErr_SetFromErrnoWithFilename(PyExc_OSError, pathname); PyErr_SetFromErrnoWithFilename(PyExc_OSError, pathname);
return -1; return -1;
@ -957,6 +962,9 @@ _Py_open_impl(const char *pathname, int flags, int gil_held)
The file descriptor is created non-inheritable. The file descriptor is created non-inheritable.
When interrupted by a signal (open() fails with EINTR), retry the syscall,
except if the Python signal handler raises an exception.
The GIL must be held. */ The GIL must be held. */
int int
_Py_open(const char *pathname, int flags) _Py_open(const char *pathname, int flags)
@ -969,7 +977,9 @@ _Py_open(const char *pathname, int flags)
/* Open a file with the specified flags (wrapper to open() function). /* Open a file with the specified flags (wrapper to open() function).
Return a file descriptor on success. Set errno and return -1 on error. Return a file descriptor on success. Set errno and return -1 on error.
The file descriptor is created non-inheritable. */ The file descriptor is created non-inheritable.
If interrupted by a signal, fail with EINTR. */
int int
_Py_open_noraise(const char *pathname, int flags) _Py_open_noraise(const char *pathname, int flags)
{ {
@ -979,7 +989,9 @@ _Py_open_noraise(const char *pathname, int flags)
/* Open a file. Use _wfopen() on Windows, encode the path to the locale /* Open a file. Use _wfopen() on Windows, encode the path to the locale
encoding and use fopen() otherwise. encoding and use fopen() otherwise.
The file descriptor is created non-inheritable). */ The file descriptor is created non-inheritable.
If interrupted by a signal, fail with EINTR. */
FILE * FILE *
_Py_wfopen(const wchar_t *path, const wchar_t *mode) _Py_wfopen(const wchar_t *path, const wchar_t *mode)
{ {
@ -1012,7 +1024,9 @@ _Py_wfopen(const wchar_t *path, const wchar_t *mode)
/* Wrapper to fopen(). /* Wrapper to fopen().
The file descriptor is created non-inheritable). */ The file descriptor is created non-inheritable.
If interrupted by a signal, fail with EINTR. */
FILE* FILE*
_Py_fopen(const char *pathname, const char *mode) _Py_fopen(const char *pathname, const char *mode)
{ {
@ -1034,11 +1048,15 @@ _Py_fopen(const char *pathname, const char *mode)
The file descriptor is created non-inheritable. The file descriptor is created non-inheritable.
When interrupted by a signal (open() fails with EINTR), retry the syscall,
except if the Python signal handler raises an exception.
The GIL must be held. */ The GIL must be held. */
FILE* FILE*
_Py_fopen_obj(PyObject *path, const char *mode) _Py_fopen_obj(PyObject *path, const char *mode)
{ {
FILE *f; FILE *f;
int async_err = 0;
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
wchar_t *wpath; wchar_t *wpath;
wchar_t wmode[10]; wchar_t wmode[10];
@ -1062,9 +1080,12 @@ _Py_fopen_obj(PyObject *path, const char *mode)
return NULL; return NULL;
} }
Py_BEGIN_ALLOW_THREADS do {
f = _wfopen(wpath, wmode); Py_BEGIN_ALLOW_THREADS
Py_END_ALLOW_THREADS f = _wfopen(wpath, wmode);
Py_END_ALLOW_THREADS
} while (f == NULL
&& errno == EINTR && !(async_err = PyErr_CheckSignals()));
#else #else
PyObject *bytes; PyObject *bytes;
char *path_bytes; char *path_bytes;
@ -1075,12 +1096,18 @@ _Py_fopen_obj(PyObject *path, const char *mode)
return NULL; return NULL;
path_bytes = PyBytes_AS_STRING(bytes); path_bytes = PyBytes_AS_STRING(bytes);
Py_BEGIN_ALLOW_THREADS do {
f = fopen(path_bytes, mode); Py_BEGIN_ALLOW_THREADS
Py_END_ALLOW_THREADS f = fopen(path_bytes, mode);
Py_END_ALLOW_THREADS
} while (f == NULL
&& errno == EINTR && !(async_err = PyErr_CheckSignals()));
Py_DECREF(bytes); Py_DECREF(bytes);
#endif #endif
if (async_err)
return NULL;
if (f == NULL) { if (f == NULL) {
PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path); PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path);
return NULL; return NULL;