This is the mail archive of the fortran@gcc.gnu.org mailing list for the GNU Fortran project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Patch, libfortran] Reduce syscalls made


Hi,

the attached simple patch slightly reduces the amount of syscalls
gfortran does.  The main issue addressed is that the Fortran standard
forbids opening the same file on multiple units. Hence when opening an
existing file, we need to go through every open file and compare the
device and inode numbers. The patch caches these values when a file is
opened, so it's no longer necessary to call fstat().

Secondly, it's not necessary to call lseek() to test whether a file is
seekable, as that information can already be found in the stat buffer.

Third, when deciding whether to use buffering or not, only buffer
regular files and block devices. While this won't solve the particular
FIFO deadlock issue that was recently reported on the mailing list, it
should at least reduce the chance of similar issues when using special
files. Also, the isatty() test is moved last, doing the cheaper tests
first.

Finally, there is a token effort to support block devices, in case
anyone is crazy enough to attempt accessing such things with gfortran.
This is not tested, and I suspect that stuff will go wrong when trying
to write past EOF.

Tested on x86_64-unknown-linux-gnu, Ok for trunk?

2010-11-08  Janne Blomqvist  <jb@gcc.gnu.org>

	* io/unix.c (struct unix_stream): Add st_dev and st_ino members.
	(fd_to_stream): Avoid unnecessary lseek() call, test isatty()
	last. Make a token effort to support block devices.
	(compare_file_filename): Use cached stat values.
	(find_file0): Likewise.
	(find_file): Likewise.


-- 
Janne Blomqvist
diff --git a/libgfortran/io/unix.c b/libgfortran/io/unix.c
index e55af18..a384f7b 100644
--- a/libgfortran/io/unix.c
+++ b/libgfortran/io/unix.c
@@ -183,7 +183,11 @@ typedef struct
 
   int ndirty;			/* Dirty bytes starting at buffer_offset */
 
-  int special_file;		/* =1 if the fd refers to a special file */
+  int special_file;             /* =1 if the fd refers to a special file */
+
+  /* Cached stat(2) values.  */
+  dev_t st_dev;
+  ino_t st_ino;
 }
 unix_stream;
 
@@ -940,18 +944,29 @@ fd_to_stream (int fd)
 
   fstat (fd, &statbuf);
 
-  if (lseek (fd, 0, SEEK_CUR) == (gfc_offset) -1)
-    s->file_length = -1;
-  else
-    s->file_length = S_ISREG (statbuf.st_mode) ? statbuf.st_size : -1;
-
+  s->st_dev = statbuf.st_dev;
+  s->st_ino = statbuf.st_ino;
   s->special_file = !S_ISREG (statbuf.st_mode);
 
-  if (isatty (s->fd) || options.all_unbuffered
+  if (S_ISREG (statbuf.st_mode))
+    s->file_length = statbuf.st_size;
+  else if (S_ISBLK (statbuf.st_mode))
+    {
+      /* Hopefully more portable than ioctl(fd, BLKGETSIZE64, &size)?  */
+      gfc_offset cur = lseek (fd, 0, SEEK_CUR);
+      s->file_length = lseek (fd, 0, SEEK_END);
+      lseek (fd, cur, SEEK_SET);
+    }
+  else
+    s->file_length = -1;
+
+  if (!(S_ISREG (statbuf.st_mode) || S_ISBLK (statbuf.st_mode))
+      || options.all_unbuffered
       ||(options.unbuffered_preconnected && 
          (s->fd == STDIN_FILENO 
           || s->fd == STDOUT_FILENO 
-          || s->fd == STDERR_FILENO)))
+          || s->fd == STDERR_FILENO))
+      || isatty (s->fd))
     raw_init (s);
   else
     buf_init (s);
@@ -1370,9 +1385,9 @@ int
 compare_file_filename (gfc_unit *u, const char *name, int len)
 {
   char path[PATH_MAX + 1];
-  gfstat_t st1;
+  gfstat_t st;
 #ifdef HAVE_WORKING_STAT
-  gfstat_t st2;
+  unix_stream *s;
 #else
 # ifdef __MINGW32__
   uint64_t id1, id2;
@@ -1385,12 +1400,12 @@ 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, &st1) < 0)
+  if (stat (path, &st) < 0)
     return 0;
 
 #ifdef HAVE_WORKING_STAT
-  fstat (((unix_stream *) (u->s))->fd, &st2);
-  return (st1.st_dev == st2.st_dev) && (st1.st_ino == st2.st_ino);
+  s = (unix_stream *) (u->s);
+  return (st.st_dev == s->st_dev) && (st.st_ino == s->st_ino);
 #else
 
 # ifdef __MINGW32__
@@ -1432,10 +1447,12 @@ find_file0 (gfc_unit *u, FIND_FILE0_DECL)
     return NULL;
 
 #ifdef HAVE_WORKING_STAT
-  if (u->s != NULL
-      && fstat (((unix_stream *) u->s)->fd, &st[1]) >= 0 &&
-      st[0].st_dev == st[1].st_dev && st[0].st_ino == st[1].st_ino)
-    return u;
+  if (u->s != NULL)
+    {
+      unix_stream *s = (unix_stream *) (u->s);
+      if (st[0].st_dev == s->st_dev && st[0].st_ino == s->st_ino)
+	return u;
+    }
 #else
 # ifdef __MINGW32__ 
   if (u->s && ((id1 = id_from_fd (((unix_stream *) u->s)->fd)) || id1))
@@ -1468,7 +1485,7 @@ gfc_unit *
 find_file (const char *file, gfc_charlen_type file_len)
 {
   char path[PATH_MAX + 1];
-  gfstat_t st[2];
+  gfstat_t st[1];
   gfc_unit *u;
 #if defined(__MINGW32__) && !HAVE_WORKING_STAT
   uint64_t id = 0ULL;

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]