aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJanne Blomqvist <jb@gcc.gnu.org>2016-10-09 21:05:56 +0300
committerJanne Blomqvist <jb@gcc.gnu.org>2016-10-09 21:05:56 +0300
commitb9233944298c0975a7cab3b1053c3ea388e9fd15 (patch)
treec793adb9e84177e3ddeb8a327cecd0543a6f697f
parentdf74f099d381013b4f52a32654f9a97c5bd39327 (diff)
downloadgcc-b9233944298c0975a7cab3b1053c3ea388e9fd15.zip
gcc-b9233944298c0975a7cab3b1053c3ea388e9fd15.tar.gz
gcc-b9233944298c0975a7cab3b1053c3ea388e9fd15.tar.bz2
PR 67585 Handle EINTR
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-09 Janne Blomqvist <jb@gcc.gnu.org> PR libfortran/67585 * io/io.h: TEMP_FAILURE_RETRY: Define macro if not found. * 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. (fd_to_stream): Handle EINTR. (tempfile_open): Likewise. (regular_file2): Likewise. (compare_file_filename): Likewise. (find_file): Likewise. (inquire_sequential): Likewise. (inquire_direct): Likewise. (inquire_formatted): Likewise. From-SVN: r240902
-rw-r--r--libgfortran/ChangeLog23
-rw-r--r--libgfortran/io/io.h15
-rw-r--r--libgfortran/io/unix.c86
3 files changed, 98 insertions, 26 deletions
diff --git a/libgfortran/ChangeLog b/libgfortran/ChangeLog
index d38646a..62b5222 100644
--- a/libgfortran/ChangeLog
+++ b/libgfortran/ChangeLog
@@ -1,3 +1,26 @@
+2016-10-09 Janne Blomqvist <jb@gcc.gnu.org>
+
+ PR libfortran/67585
+ * io/io.h: TEMP_FAILURE_RETRY: Define macro if not found.
+ * 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.
+ (fd_to_stream): Handle EINTR.
+ (tempfile_open): Likewise.
+ (regular_file2): Likewise.
+ (compare_file_filename): Likewise.
+ (find_file): Likewise.
+ (inquire_sequential): Likewise.
+ (inquire_direct): Likewise.
+ (inquire_formatted): Likewise.
+
2016-10-05 Jerry DeLisle <jvdelisle@gcc.gnu.org>
PR fortran/77868
diff --git a/libgfortran/io/io.h b/libgfortran/io/io.h
index 87c3558..ea93fba 100644
--- a/libgfortran/io/io.h
+++ b/libgfortran/io/io.h
@@ -660,6 +660,21 @@ typedef struct gfc_saved_unit
}
gfc_saved_unit;
+/* TEMP_FAILURE_RETRY macro from glibc. */
+
+#ifndef TEMP_FAILURE_RETRY
+/* Evaluate EXPRESSION, and repeat as long as it returns -1 with `errno'
+ set to EINTR. */
+
+# define TEMP_FAILURE_RETRY(expression) \
+ (__extension__ \
+ ({ long int __result; \
+ do __result = (long int) (expression); \
+ while (__result == -1L && errno == EINTR); \
+ __result; }))
+#endif
+
+
/* unit.c */
/* Maximum file offset, computed at library initialization time. */
diff --git a/libgfortran/io/unix.c b/libgfortran/io/unix.c
index 29818cd..1e84c42 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,33 @@ 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;
+ if (TEMP_FAILURE_RETRY (fstat (s->fd, &statbuf)) == -1)
+ return -1;
if (S_ISREG (statbuf.st_mode))
return statbuf.st_size;
else
@@ -390,7 +408,9 @@ 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);
+ if (TEMP_FAILURE_RETRY (ftruncate (s->fd, length)) == -1)
+ return -1;
+ return 0;
#elif defined HAVE_CHSIZE
return chsize (s->fd, length);
#else
@@ -409,7 +429,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 +493,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 +548,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 +617,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;
}
@@ -1025,7 +1055,7 @@ fd_to_stream (int fd, bool unformatted)
/* Get the current length of the file. */
- if (fstat (fd, &statbuf) == -1)
+ if (TEMP_FAILURE_RETRY (fstat (fd, &statbuf)) == -1)
{
s->st_dev = s->st_ino = -1;
s->file_length = 0;
@@ -1134,9 +1164,9 @@ tempfile_open (const char *tempdir, char **fname)
#endif
#if defined(HAVE_MKOSTEMP) && defined(O_CLOEXEC)
- fd = mkostemp (template, O_CLOEXEC);
+ TEMP_FAILURE_RETRY (fd = mkostemp (template, O_CLOEXEC));
#else
- fd = mkstemp (template);
+ TEMP_FAILURE_RETRY (fd = mkstemp (template));
set_close_on_exec (fd);
#endif
@@ -1178,7 +1208,7 @@ tempfile_open (const char *tempdir, char **fname)
continue;
}
- fd = open (template, flags, S_IRUSR | S_IWUSR);
+ TEMP_FAILURE_RETRY (fd = open (template, flags, S_IRUSR | S_IWUSR));
}
while (fd == -1 && errno == EEXIST);
#ifndef O_CLOEXEC
@@ -1355,7 +1385,7 @@ regular_file2 (const char *path, st_parameter_open *opp, unit_flags *flags)
#endif
mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
- fd = open (path, rwflag | crflag, mode);
+ TEMP_FAILURE_RETRY (fd = open (path, rwflag | crflag, mode));
if (flags->action != ACTION_UNSPECIFIED)
return fd;
@@ -1373,7 +1403,7 @@ regular_file2 (const char *path, st_parameter_open *opp, unit_flags *flags)
crflag2 = crflag & ~(O_CREAT);
else
crflag2 = crflag;
- fd = open (path, rwflag | crflag2, mode);
+ TEMP_FAILURE_RETRY (fd = open (path, rwflag | crflag2, mode));
if (fd >=0)
{
flags->action = ACTION_READ;
@@ -1385,7 +1415,7 @@ regular_file2 (const char *path, st_parameter_open *opp, unit_flags *flags)
/* retry for write-only access */
rwflag = O_WRONLY;
- fd = open (path, rwflag | crflag, mode);
+ TEMP_FAILURE_RETRY (fd = open (path, rwflag | crflag, mode));
if (fd >=0)
{
flags->action = ACTION_WRITE;
@@ -1512,7 +1542,7 @@ compare_file_filename (gfc_unit *u, const char *name, int len)
/* If the filename doesn't exist, then there is no match with the
* existing file. */
- if (stat (path, &st) < 0)
+ if (TEMP_FAILURE_RETRY (stat (path, &st)) < 0)
{
ret = 0;
goto done;
@@ -1614,7 +1644,7 @@ find_file (const char *file, gfc_charlen_type file_len)
char *path = fc_strdup (file, file_len);
- if (stat (path, &st[0]) < 0)
+ if (TEMP_FAILURE_RETRY (stat (path, &st[0])) < 0)
{
u = NULL;
goto done;
@@ -1742,7 +1772,8 @@ file_size (const char *file, gfc_charlen_type file_len)
{
char *path = fc_strdup (file, file_len);
struct stat statbuf;
- int err = stat (path, &statbuf);
+ int err;
+ TEMP_FAILURE_RETRY (err = stat (path, &statbuf));
free (path);
if (err == -1)
return -1;
@@ -1764,7 +1795,8 @@ inquire_sequential (const char *string, int len)
return unknown;
char *path = fc_strdup (string, len);
- int err = stat (path, &statbuf);
+ int err;
+ TEMP_FAILURE_RETRY (err = stat (path, &statbuf));
free (path);
if (err == -1)
return unknown;
@@ -1792,7 +1824,8 @@ inquire_direct (const char *string, int len)
return unknown;
char *path = fc_strdup (string, len);
- int err = stat (path, &statbuf);
+ int err;
+ TEMP_FAILURE_RETRY (err = stat (path, &statbuf));
free (path);
if (err == -1)
return unknown;
@@ -1820,7 +1853,8 @@ inquire_formatted (const char *string, int len)
return unknown;
char *path = fc_strdup (string, len);
- int err = stat (path, &statbuf);
+ int err;
+ TEMP_FAILURE_RETRY (err = stat (path, &statbuf));
free (path);
if (err == -1)
return unknown;