diff options
author | Victor Stinner <victor.stinner@gmail.com> | 2015-03-18 08:52:54 (GMT) |
---|---|---|
committer | Victor Stinner <victor.stinner@gmail.com> | 2015-03-18 08:52:54 (GMT) |
commit | a47fc5c2ddcf86eb3cb1ad628d04bf3764cfce59 (patch) | |
tree | 4eba4aeb0e12436a1c9a811bbac87951b19bc27f | |
parent | 9c1a9b2657b5e39c6359698e160cb2b7e6df1193 (diff) | |
download | cpython-a47fc5c2ddcf86eb3cb1ad628d04bf3764cfce59.zip cpython-a47fc5c2ddcf86eb3cb1ad628d04bf3764cfce59.tar.gz cpython-a47fc5c2ddcf86eb3cb1ad628d04bf3764cfce59.tar.bz2 |
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.
-rw-r--r-- | Python/fileutils.c | 53 |
1 files changed, 40 insertions, 13 deletions
diff --git a/Python/fileutils.c b/Python/fileutils.c index a198625..fa481ae 100644 --- a/Python/fileutils.c +++ b/Python/fileutils.c @@ -912,6 +912,7 @@ static int _Py_open_impl(const char *pathname, int flags, int gil_held) { int fd; + int async_err = 0; #ifndef MS_WINDOWS int *atomic_flag_works; #endif @@ -926,10 +927,14 @@ _Py_open_impl(const char *pathname, int flags, int gil_held) #endif if (gil_held) { - Py_BEGIN_ALLOW_THREADS - fd = open(pathname, flags); - Py_END_ALLOW_THREADS - + do { + Py_BEGIN_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) { PyErr_SetFromErrnoWithFilename(PyExc_OSError, pathname); return -1; @@ -957,6 +962,9 @@ _Py_open_impl(const char *pathname, int flags, int gil_held) 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. */ int _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). 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 _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 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 * _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(). - The file descriptor is created non-inheritable). */ + The file descriptor is created non-inheritable. + + If interrupted by a signal, fail with EINTR. */ FILE* _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. + 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. */ FILE* _Py_fopen_obj(PyObject *path, const char *mode) { FILE *f; + int async_err = 0; #ifdef MS_WINDOWS wchar_t *wpath; wchar_t wmode[10]; @@ -1062,9 +1080,12 @@ _Py_fopen_obj(PyObject *path, const char *mode) return NULL; } - Py_BEGIN_ALLOW_THREADS - f = _wfopen(wpath, wmode); - Py_END_ALLOW_THREADS + do { + Py_BEGIN_ALLOW_THREADS + f = _wfopen(wpath, wmode); + Py_END_ALLOW_THREADS + } while (f == NULL + && errno == EINTR && !(async_err = PyErr_CheckSignals())); #else PyObject *bytes; char *path_bytes; @@ -1075,12 +1096,18 @@ _Py_fopen_obj(PyObject *path, const char *mode) return NULL; path_bytes = PyBytes_AS_STRING(bytes); - Py_BEGIN_ALLOW_THREADS - f = fopen(path_bytes, mode); - Py_END_ALLOW_THREADS + do { + Py_BEGIN_ALLOW_THREADS + f = fopen(path_bytes, mode); + Py_END_ALLOW_THREADS + } while (f == NULL + && errno == EINTR && !(async_err = PyErr_CheckSignals())); Py_DECREF(bytes); #endif + if (async_err) + return NULL; + if (f == NULL) { PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path); return NULL; |