From: Janne Blomqvist Date: Sun, 9 Oct 2016 18:05:56 +0000 (+0300) Subject: PR 67585 Handle EINTR X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=b9233944298c0975a7cab3b1053c3ea388e9fd15;p=gcc.git 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 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 --- diff --git a/libgfortran/ChangeLog b/libgfortran/ChangeLog index d38646ac8b7..62b52226090 100644 --- a/libgfortran/ChangeLog +++ b/libgfortran/ChangeLog @@ -1,3 +1,26 @@ +2016-10-09 Janne Blomqvist + + 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 PR fortran/77868 diff --git a/libgfortran/io/io.h b/libgfortran/io/io.h index 87c35583754..ea93fbaf99d 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 29818cd7a14..1e84c42dd3a 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;