This is the mail archive of the
fortran@gcc.gnu.org
mailing list for the GNU Fortran project.
[PATCH, libgfortran] PR 67585 Handle EINTR
- From: Janne Blomqvist <blomqvist dot janne at gmail dot com>
- To: fortran at gcc dot gnu dot org, gcc-patches at gcc dot gnu dot org
- Date: Fri, 7 Oct 2016 15:26:26 +0300
- Subject: [PATCH, libgfortran] PR 67585 Handle EINTR
- Authentication-results: sourceware.org; auth=none
Many POSIX systems have the bad habit of not restarting interrupted
syscalls. On these systems it's up to the user to check for an error
with errno == EINTR and restart manually. This patch does this for
libgfortran, so that GFortran users don't have to do it.
2016-10-07 Janne Blomqvist <jb@gcc.gnu.org>
PR libfortran/67585
* io/unix.c (raw_read): Handle EINTR.
(raw_write): Check for return value -1.
(raw_seek): Handle EINTR.
(raw_tell): Likewise.
(raw_size): Likewise.
(raw_truncate): Likewise.
(raw_close): Likewise.
(buf_flush): Call raw_seek instead of lseek.
(buf_read): Likewise.
(buf_write): Likewise.
Regtested on x86_64-pc-linux-gnu. Ok for trunk?
---
libgfortran/io/unix.c | 64 ++++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 51 insertions(+), 13 deletions(-)
diff --git a/libgfortran/io/unix.c b/libgfortran/io/unix.c
index 29818cd..43e33c8 100644
--- a/libgfortran/io/unix.c
+++ b/libgfortran/io/unix.c
@@ -298,8 +298,15 @@ static ssize_t
raw_read (unix_stream * s, void * buf, ssize_t nbyte)
{
/* For read we can't do I/O in a loop like raw_write does, because
- that will break applications that wait for interactive I/O. */
- return read (s->fd, buf, nbyte);
+ that will break applications that wait for interactive I/O. We
+ still can loop around EINTR, though. */
+ while (true)
+ {
+ ssize_t trans = read (s->fd, buf, nbyte);
+ if (trans == -1 && errno == EINTR)
+ continue;
+ return trans;
+ }
}
static ssize_t
@@ -316,7 +323,7 @@ raw_write (unix_stream * s, const void * buf, ssize_t nbyte)
while (bytes_left > 0)
{
trans = write (s->fd, buf_st, bytes_left);
- if (trans < 0)
+ if (trans == -1)
{
if (errno == EINTR)
continue;
@@ -333,22 +340,37 @@ raw_write (unix_stream * s, const void * buf, ssize_t nbyte)
static gfc_offset
raw_seek (unix_stream * s, gfc_offset offset, int whence)
{
- return lseek (s->fd, offset, whence);
+ while (true)
+ {
+ gfc_offset off = lseek (s->fd, offset, whence);
+ if (off == (gfc_offset) -1 && errno == EINTR)
+ continue;
+ return off;
+ }
}
static gfc_offset
raw_tell (unix_stream * s)
{
- return lseek (s->fd, 0, SEEK_CUR);
+ while (true)
+ {
+ gfc_offset off = lseek (s->fd, 0, SEEK_CUR);
+ if (off == (gfc_offset) -1 && errno == EINTR)
+ continue;
+ return off;
+ }
}
static gfc_offset
raw_size (unix_stream * s)
{
struct stat statbuf;
- int ret = fstat (s->fd, &statbuf);
- if (ret == -1)
- return ret;
+ while (fstat (s->fd, &statbuf) == -1)
+ {
+ if (errno == EINTR)
+ continue;
+ return -1;
+ }
if (S_ISREG (statbuf.st_mode))
return statbuf.st_size;
else
@@ -390,7 +412,13 @@ raw_truncate (unix_stream * s, gfc_offset length)
lseek (s->fd, cur, SEEK_SET);
return -1;
#elif defined HAVE_FTRUNCATE
- return ftruncate (s->fd, length);
+ while (ftruncate (s->fd, length) == -1)
+ {
+ if (errno == EINTR)
+ continue;
+ return -1;
+ }
+ return 0;
#elif defined HAVE_CHSIZE
return chsize (s->fd, length);
#else
@@ -409,7 +437,17 @@ raw_close (unix_stream * s)
else if (s->fd != STDOUT_FILENO
&& s->fd != STDERR_FILENO
&& s->fd != STDIN_FILENO)
- retval = close (s->fd);
+ {
+ retval = close (s->fd);
+ /* close() and EINTR is special, as the file descriptor is
+ deallocated before doing anything that might cause the
+ operation to be interrupted. Thus if we get EINTR the best we
+ can do is ignore it and continue (otherwise if we try again
+ the file descriptor may have been allocated again to some
+ other file). */
+ if (retval == -1 && errno == EINTR)
+ retval = errno = 0;
+ }
else
retval = 0;
free (s);
@@ -463,7 +501,7 @@ buf_flush (unix_stream * s)
return 0;
if (s->physical_offset != s->buffer_offset
- && lseek (s->fd, s->buffer_offset, SEEK_SET) < 0)
+ && raw_seek (s, s->buffer_offset, SEEK_SET) < 0)
return -1;
writelen = raw_write (s, s->buffer, s->ndirty);
@@ -518,7 +556,7 @@ buf_read (unix_stream * s, void * buf, ssize_t nbyte)
to_read = nbyte - nread;
new_logical = s->logical_offset + nread;
if (s->physical_offset != new_logical
- && lseek (s->fd, new_logical, SEEK_SET) < 0)
+ && raw_seek (s, new_logical, SEEK_SET) < 0)
return -1;
s->buffer_offset = s->physical_offset = new_logical;
if (to_read <= BUFFER_SIZE/2)
@@ -587,7 +625,7 @@ buf_write (unix_stream * s, const void * buf, ssize_t nbyte)
{
if (s->physical_offset != s->logical_offset)
{
- if (lseek (s->fd, s->logical_offset, SEEK_SET) < 0)
+ if (raw_seek (s, s->logical_offset, SEEK_SET) < 0)
return -1;
s->physical_offset = s->logical_offset;
}
--
2.7.4