public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH, libgfortran] PR 67585 Handle EINTR
@ 2016-10-07 12:26 Janne Blomqvist
  2016-10-07 12:41 ` FX
  2016-10-09 13:59 ` [PATCH] " Janne Blomqvist
  0 siblings, 2 replies; 11+ messages in thread
From: Janne Blomqvist @ 2016-10-07 12:26 UTC (permalink / raw)
  To: fortran, gcc-patches

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

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2016-10-09 13:59 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-10-07 12:26 [PATCH, libgfortran] PR 67585 Handle EINTR Janne Blomqvist
2016-10-07 12:41 ` FX
2016-10-07 12:59   ` Janne Blomqvist
2016-10-07 14:50     ` Fritz Reese
2016-10-07 16:09       ` Janne Blomqvist
2016-10-07 16:42         ` Jack Howarth
2016-10-07 19:55           ` Mike Stump
2016-10-07 19:46       ` Mike Stump
2016-10-07 19:26     ` Mike Stump
2016-10-07 19:18   ` Mike Stump
2016-10-09 13:59 ` [PATCH] " Janne Blomqvist

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).