mirror of
https://github.com/python/cpython.git
synced 2025-10-09 16:34:44 +00:00
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:
parent
9c1a9b2657
commit
a47fc5c2dd
1 changed files with 40 additions and 13 deletions
|
@ -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;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue