summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@gmail.com>2015-04-01 16:34:45 (GMT)
committerVictor Stinner <victor.stinner@gmail.com>2015-04-01 16:34:45 (GMT)
commit82c3e4599d067f7dc72cea1530d3a26ba1682028 (patch)
treefe7baed4b7cc0b58372f77c7bda499ef653ea0de /Python
parent81541f448066142c04fae736c3dda23b184c32be (diff)
downloadcpython-82c3e4599d067f7dc72cea1530d3a26ba1682028.zip
cpython-82c3e4599d067f7dc72cea1530d3a26ba1682028.tar.gz
cpython-82c3e4599d067f7dc72cea1530d3a26ba1682028.tar.bz2
Issue #23836: Add _Py_write_noraise() function
Helper to write() which retries write() if it is interrupted by a signal (fails with EINTR).
Diffstat (limited to 'Python')
-rw-r--r--Python/fileutils.c131
1 files changed, 83 insertions, 48 deletions
diff --git a/Python/fileutils.c b/Python/fileutils.c
index daaad2a..e4c5241 100644
--- a/Python/fileutils.c
+++ b/Python/fileutils.c
@@ -1124,18 +1124,18 @@ _Py_fopen_obj(PyObject *path, const char *mode)
}
/* Read count bytes from fd into buf.
- *
- * On success, return the number of read bytes, it can be lower than count.
- * If the current file offset is at or past the end of file, no bytes are read,
- * and read() returns zero.
- *
- * On error, raise an exception, set errno and return -1.
- *
- * When interrupted by a signal (read() fails with EINTR), retry the syscall.
- * If the Python signal handler raises an exception, the function returns -1
- * (the syscall is not retried).
- *
- * The GIL must be held. */
+
+ On success, return the number of read bytes, it can be lower than count.
+ If the current file offset is at or past the end of file, no bytes are read,
+ and read() returns zero.
+
+ On error, raise an exception, set errno and return -1.
+
+ When interrupted by a signal (read() fails with EINTR), retry the syscall.
+ If the Python signal handler raises an exception, the function returns -1
+ (the syscall is not retried).
+
+ Release the GIL to call read(). The caller must hold the GIL. */
Py_ssize_t
_Py_read(int fd, void *buf, size_t count)
{
@@ -1200,34 +1200,20 @@ _Py_read(int fd, void *buf, size_t count)
return n;
}
-/* Write count bytes of buf into fd.
- *
- * -On success, return the number of written bytes, it can be lower than count
- * including 0
- * - On error, raise an exception, set errno and return -1.
- *
- * When interrupted by a signal (write() fails with EINTR), retry the syscall.
- * If the Python signal handler raises an exception, the function returns -1
- * (the syscall is not retried).
- *
- * The GIL must be held. */
-Py_ssize_t
-_Py_write(int fd, const void *buf, size_t count)
+static Py_ssize_t
+_Py_write_impl(int fd, const void *buf, size_t count, int gil_held)
{
Py_ssize_t n;
int err;
int async_err = 0;
- /* _Py_write() must not be called with an exception set, otherwise the
- * caller may think that write() was interrupted by a signal and the signal
- * handler raised an exception. */
- assert(!PyErr_Occurred());
-
if (!_PyVerify_fd(fd)) {
- /* save/restore errno because PyErr_SetFromErrno() can modify it */
- err = errno;
- PyErr_SetFromErrno(PyExc_OSError);
- errno = err;
+ if (gil_held) {
+ /* save/restore errno because PyErr_SetFromErrno() can modify it */
+ err = errno;
+ PyErr_SetFromErrno(PyExc_OSError);
+ errno = err;
+ }
return -1;
}
@@ -1249,30 +1235,45 @@ _Py_write(int fd, const void *buf, size_t count)
}
#endif
- do {
- Py_BEGIN_ALLOW_THREADS
- errno = 0;
+ if (gil_held) {
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ errno = 0;
#ifdef MS_WINDOWS
- n = write(fd, buf, (int)count);
+ n = write(fd, buf, (int)count);
#else
- n = write(fd, buf, count);
+ n = write(fd, buf, count);
#endif
- /* save/restore errno because PyErr_CheckSignals()
- * and PyErr_SetFromErrno() can modify it */
- err = errno;
- Py_END_ALLOW_THREADS
- } while (n < 0 && errno == EINTR &&
- !(async_err = PyErr_CheckSignals()));
+ /* save/restore errno because PyErr_CheckSignals()
+ * and PyErr_SetFromErrno() can modify it */
+ err = errno;
+ Py_END_ALLOW_THREADS
+ } while (n < 0 && err == EINTR &&
+ !(async_err = PyErr_CheckSignals()));
+ }
+ else {
+ do {
+ errno = 0;
+#ifdef MS_WINDOWS
+ n = write(fd, buf, (int)count);
+#else
+ n = write(fd, buf, count);
+#endif
+ err = errno;
+ } while (n < 0 && err == EINTR);
+ }
if (async_err) {
/* write() was interrupted by a signal (failed with EINTR)
- * and the Python signal handler raised an exception */
+ and the Python signal handler raised an exception (if gil_held is
+ nonzero). */
errno = err;
- assert(errno == EINTR && PyErr_Occurred());
+ assert(errno == EINTR && (!gil_held || PyErr_Occurred()));
return -1;
}
if (n < 0) {
- PyErr_SetFromErrno(PyExc_OSError);
+ if (gil_held)
+ PyErr_SetFromErrno(PyExc_OSError);
errno = err;
return -1;
}
@@ -1280,6 +1281,40 @@ _Py_write(int fd, const void *buf, size_t count)
return n;
}
+/* Write count bytes of buf into fd.
+
+ On success, return the number of written bytes, it can be lower than count
+ including 0. On error, raise an exception, set errno and return -1.
+
+ When interrupted by a signal (write() fails with EINTR), retry the syscall.
+ If the Python signal handler raises an exception, the function returns -1
+ (the syscall is not retried).
+
+ Release the GIL to call write(). The caller must hold the GIL. */
+Py_ssize_t
+_Py_write(int fd, const void *buf, size_t count)
+{
+ /* _Py_write() must not be called with an exception set, otherwise the
+ * caller may think that write() was interrupted by a signal and the signal
+ * handler raised an exception. */
+ assert(!PyErr_Occurred());
+
+ return _Py_write_impl(fd, buf, count, 1);
+}
+
+/* Write count bytes of buf into fd.
+ *
+ * On success, return the number of written bytes, it can be lower than count
+ * including 0. On error, set errno and return -1.
+ *
+ * When interrupted by a signal (write() fails with EINTR), retry the syscall
+ * without calling the Python signal handler. */
+Py_ssize_t
+_Py_write_noraise(int fd, const void *buf, size_t count)
+{
+ return _Py_write_impl(fd, buf, count, 0);
+}
+
#ifdef HAVE_READLINK
/* Read value of symbolic link. Encode the path to the locale encoding, decode