summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNir Soffer <nirsof@gmail.com>2017-12-01 01:18:58 (GMT)
committerVictor Stinner <victor.stinner@gmail.com>2017-12-01 01:18:58 (GMT)
commit6a89481680b921e7b317c29877bdda9a6031e5ad (patch)
treed5292d62fba5e604eda83869670acde7c51db492
parentc319eeeb45043ee45384b8064c53ddbfde1673cd (diff)
downloadcpython-6a89481680b921e7b317c29877bdda9a6031e5ad.zip
cpython-6a89481680b921e7b317c29877bdda9a6031e5ad.tar.gz
cpython-6a89481680b921e7b317c29877bdda9a6031e5ad.tar.bz2
bpo-32186: Release the GIL during lseek and fstat (#4652)
In _io_FileIO_readall_impl(), lseek() and _Py_fstat_noraise() were called without releasing the GIL. This can cause all threads to hang for unlimited time when calling FileIO.read() and the NFS server is not accessible.
-rw-r--r--Misc/NEWS.d/next/Library/2017-11-30-20-38-16.bpo-32186.O42bVe.rst3
-rw-r--r--Modules/_io/fileio.c6
2 files changed, 8 insertions, 1 deletions
diff --git a/Misc/NEWS.d/next/Library/2017-11-30-20-38-16.bpo-32186.O42bVe.rst b/Misc/NEWS.d/next/Library/2017-11-30-20-38-16.bpo-32186.O42bVe.rst
new file mode 100644
index 0000000..ea696c6
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2017-11-30-20-38-16.bpo-32186.O42bVe.rst
@@ -0,0 +1,3 @@
+io.FileIO.readall() and io.FileIO.read() now release the GIL when
+getting the file size. Fixed hang of all threads with inaccessible NFS
+server. Patch by Nir Soffer.
diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c
index b6755b8..269142c 100644
--- a/Modules/_io/fileio.c
+++ b/Modules/_io/fileio.c
@@ -683,10 +683,12 @@ _io_FileIO_readall_impl(fileio *self)
Py_ssize_t bytes_read = 0;
Py_ssize_t n;
size_t bufsize;
+ int fstat_result;
if (self->fd < 0)
return err_closed();
+ Py_BEGIN_ALLOW_THREADS
_Py_BEGIN_SUPPRESS_IPH
#ifdef MS_WINDOWS
pos = _lseeki64(self->fd, 0L, SEEK_CUR);
@@ -694,8 +696,10 @@ _io_FileIO_readall_impl(fileio *self)
pos = lseek(self->fd, 0L, SEEK_CUR);
#endif
_Py_END_SUPPRESS_IPH
+ fstat_result = _Py_fstat_noraise(self->fd, &status);
+ Py_END_ALLOW_THREADS
- if (_Py_fstat_noraise(self->fd, &status) == 0)
+ if (fstat_result == 0)
end = status.st_size;
else
end = (Py_off_t)-1;