This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC 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, libgfortran] PR 25561 Part 1.1/2 Minor improvements to part 1


Hello,

the attached patch does some minor improvements on top of part 1 of the
patch ( http://gcc.gnu.org/ml/gcc-patches/2008-05/msg00769.html ) which
was committed earlier today. As the patch already was quite big, I
didn't want to make reviewers trawl through it again just due to these
minor changes.

It changes the fbuf structure such that the current position in the
structure is an offset from the beginning rather than a pointer. This
makes the buffer manipulation functions a bit simpler.

The main change is that in fbuf_alloc, it avoids keeping already flushed
bytes in case the request doesn't fit into the current buffer. This
avoids the buffer growing without bound if the user is executing many
advance='no' write statements (e.g. in a loop).

It also implements Thomas Koenigs suggestion to use the provided RECL
(if available) as the initial buffer size. Thanks, Thomas!

Regtested on i686-pc-linux-gnu, Ok for trunk?

--
Janne Blomqvist
2008-05-15  Janne Blomqvist  <jb@gcc.gnu.org>

	PR libfortran/25561
	* io/io.h (struct fbuf): Change pointer to position offset.
	* io/fbuf.c (fbuf_init): Reduce default size of buffer, ptr=>pos
	changes.
	(fbuf_reset): ptr=>pos changes.
	(fbuf_alloc): If the request doesn't fit, don't waste memory by
	keeping flushed bytes. ptr=>pos changes.
	(fbuf_flush): ptr=>pos changes.
	(fbuf_seek): Don't seek past the left tab limit, don't update active
	byte count.
	* io/open.c (new_unit): If RECL has been specified, used that as
	initial buffer size.
diff --git a/libgfortran/io/fbuf.c b/libgfortran/io/fbuf.c
index e34fc75..a0d033b 100644
--- a/libgfortran/io/fbuf.c
+++ b/libgfortran/io/fbuf.c
@@ -37,20 +37,19 @@ void
 fbuf_init (gfc_unit * u, size_t len)
 {
   if (len == 0)
-    len = 4096;			/* Default size one page.  */
+    len = 512;			/* Default size.  */
 
   u->fbuf = get_mem (sizeof (fbuf));
-  u->fbuf->buf = u->fbuf->ptr = get_mem (len);
+  u->fbuf->buf = get_mem (len);
   u->fbuf->len = len;
-  u->fbuf->act = u->fbuf->flushed = 0;
+  u->fbuf->act = u->fbuf->flushed = u->fbuf->pos = 0;
 }
 
 
 void
 fbuf_reset (gfc_unit * u)
 {
-  u->fbuf->act = u->fbuf->flushed = 0;
-  u->fbuf->ptr = u->fbuf->buf;
+  u->fbuf->act = u->fbuf->flushed = u->fbuf->pos = 0;
 }
 
 
@@ -67,33 +66,65 @@ fbuf_destroy (gfc_unit * u)
 
 /* Return a pointer to the current position in the buffer, and increase
    the pointer by len. Makes sure that the buffer is big enough, 
-   reallocating if necessary.  */
+   reallocating if necessary. If the buffer is not big enough, there are
+   three cases to consider:
+   1. If we haven't flushed anything, realloc
+   2. If we have flushed enough that by discarding the flushed bytes
+      the request fits into the buffer, do that.
+   3. Else allocate a new buffer, memcpy unflushed active bytes from old
+      buffer. */
 
 char *
 fbuf_alloc (gfc_unit * u, size_t len)
 {
-  size_t newlen, ptrpos;
+  size_t newlen;
   char *dest;
-  if (u->fbuf->ptr + len > u->fbuf->buf + u->fbuf->len)
+  if (u->fbuf->pos + len > u->fbuf->len)
     {
-      /* Round up to nearest multiple of the current buffer length.  */
-      ptrpos = u->fbuf->ptr - u->fbuf->buf;
-      newlen = ((ptrpos + len) / u->fbuf->len + 1) * u->fbuf->len;
-      dest = realloc (u->fbuf->buf, newlen);
-      if (dest == NULL)
-	return NULL;
-      u->fbuf->buf = dest;
-      u->fbuf->ptr = dest + ptrpos;
-      u->fbuf->len = newlen;
+      if (u->fbuf->flushed == 0)
+	{
+	  /* Round up to nearest multiple of the current buffer length.  */
+	  newlen = ((u->fbuf->pos + len) / u->fbuf->len + 1) * u->fbuf->len;
+	  dest = realloc (u->fbuf->buf, newlen);
+	  if (dest == NULL)
+	    return NULL;
+	  u->fbuf->buf = dest;
+	  u->fbuf->len = newlen;
+	}
+      else if (u->fbuf->act - u->fbuf->flushed + len < u->fbuf->len)
+	{
+	  memmove (u->fbuf->buf, u->fbuf->buf + u->fbuf->flushed,
+		   u->fbuf->act - u->fbuf->flushed);
+	  u->fbuf->act -= u->fbuf->flushed;
+	  u->fbuf->pos -= u->fbuf->flushed;
+	  u->fbuf->flushed = 0;
+	}
+      else
+	{
+	  /* Most general case, flushed != 0, request doesn't fit.  */
+	  newlen = ((u->fbuf->pos - u->fbuf->flushed + len)
+		    / u->fbuf->len + 1) * u->fbuf->len;
+	  dest = get_mem (newlen);
+	  memcpy (dest, u->fbuf->buf + u->fbuf->flushed,
+		  u->fbuf->act - u->fbuf->flushed);
+	  u->fbuf->act -= u->fbuf->flushed;
+	  u->fbuf->pos -= u->fbuf->flushed;
+	  u->fbuf->flushed = 0;
+	  u->fbuf->buf = dest;
+	  u->fbuf->len = newlen;
+	}
     }
-  dest = u->fbuf->ptr;
-  u->fbuf->ptr += len;
-  if ((size_t) (u->fbuf->ptr - u->fbuf->buf) > u->fbuf->act)
-    u->fbuf->act = u->fbuf->ptr - u->fbuf->buf;
+
+  dest = u->fbuf->buf + u->fbuf->pos;
+  u->fbuf->pos += len;
+  if (u->fbuf->pos > u->fbuf->act)
+    u->fbuf->act = u->fbuf->pos;
   return dest;
 }
 
 
+
+
 int
 fbuf_flush (gfc_unit * u, int record_done)
 {
@@ -107,7 +138,7 @@ fbuf_flush (gfc_unit * u, int record_done)
       if (record_done)
         nbytes = u->fbuf->act - u->fbuf->flushed;
       else	
-        nbytes = u->fbuf->ptr - u->fbuf->buf - u->fbuf->flushed;	
+        nbytes = u->fbuf->pos - u->fbuf->flushed;	
       status = swrite (u->s, u->fbuf->buf + u->fbuf->flushed, &nbytes);
       u->fbuf->flushed += nbytes;
     }
@@ -122,11 +153,12 @@ fbuf_flush (gfc_unit * u, int record_done)
 int
 fbuf_seek (gfc_unit * u, gfc_offset off)
 {
-  gfc_offset pos = u->fbuf->ptr - u->fbuf->buf + off;
-  if (pos < 0)
+  gfc_offset pos = u->fbuf->pos + off;
+  /* Moving to the left past the flushed marked would imply moving past
+     the left tab limit, which is never allowed. So return error if
+     that is attempted.  */
+  if (pos < u->fbuf->flushed)
     return -1;
-  u->fbuf->ptr = u->fbuf->buf + pos;
-  if (pos > (gfc_offset) u->fbuf->act)
-    u->fbuf->act = pos;
+  u->fbuf->pos = pos;
   return 0;
 }
diff --git a/libgfortran/io/io.h b/libgfortran/io/io.h
index e554d8c..7f9f38f 100644
--- a/libgfortran/io/io.h
+++ b/libgfortran/io/io.h
@@ -537,7 +537,7 @@ typedef struct fbuf
   size_t len;			/* Length of buffer.  */
   size_t act;			/* Active bytes in buffer.  */
   size_t flushed;		/* Flushed bytes from beginning of buffer.  */
-  char *ptr;			/* Current position in buffer.  */
+  size_t pos;			/* Current position in buffer.  */
 }
 fbuf;
 
diff --git a/libgfortran/io/open.c b/libgfortran/io/open.c
index e16386c..844fa5c 100644
--- a/libgfortran/io/open.c
+++ b/libgfortran/io/open.c
@@ -628,9 +628,15 @@ new_unit (st_parameter_open *opp, gfc_unit *u, unit_flags * flags)
     free_mem (opp->file);
     
   if (flags->form == FORM_FORMATTED && (flags->action != ACTION_READ))
-    fbuf_init (u, 0);
+    {
+      if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN))
+        fbuf_init (u, u->recl);
+      else
+        fbuf_init (u, 0);
+    }
   else
     u->fbuf = NULL;
+
     
     
   return u;

Attachment: signature.asc
Description: OpenPGP digital signature


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