bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: 'fflush' test failure on Cygwin


From: Bruno Haible
Subject: Re: 'fflush' test failure on Cygwin
Date: Fri, 13 Apr 2007 03:30:13 +0200
User-agent: KMail/1.5.4

Eric Blake wrote:
> >   File offset is wrong.
> >   FAIL: test-fflush.exe
> >
> > In test-fflush.c line 70, the return value from lseek() is 10 instead of the
> > expected 5.
> 
> That is due to a bug in newlib's fflush that I fixed on 2006-12-14.
> 
> I personally don't use a cygwin that old, nor do I recommend it to others

But it's the goal of the 'fflush' module to make this test work, no?

> But seeing as how the failure symptom is the same as that of MacOSX,

Indeed, on MacOS X 10.3.9, the lseek call in test-fflush.c:70 also yields 10,
not 5.

> I'm wondering if anyone has better ideas of how to force stdio to reposition
> the offset of the underlying fd when fflush (or fpurge) followed by fseek
> is not powerful enough to do the same.  I could always do a raw lseek
> myself, but that makes me worry that if stdio has read in a buffer, then
> stdio will be confused because the fd changed behind its back.

After looking at the MacOS X source files
   Libc-320.1.3/stdio/FreBSD/fflush.c
   Libc-320.1.3/stdio/FreBSD/fseek.c
(from http://developer.apple.com/opensource/ -> Darwin -> MacOS X 10.3.9
Source -> Libc-320.1.3) for two hours, here's what I think:


1) fpurge exists on MacOS X, but only clears the buffer, without changing
   the file descriptor's position in the kernel. So it needs this change
   (otherwise the stream's position before the fflush() call is lost):

*** lib/fflush.c        2007-04-13 00:15:11.000000000 +0200
--- lib/fflush.c        2007-04-13 02:44:10.000000000 +0200
***************
*** 57,63 ****
    /* To get here, we must be flushing a seekable input stream, so the
       semantics of fpurge are now appropriate.  */
  #if HAVE_FPURGE
!   result = fpurge (stream);
  #elif HAVE___FPURGE
    /* __fpurge has no return value, and on Solaris, we can't even trust
       errno.  So assume it succeeds.  */
--- 57,72 ----
    /* To get here, we must be flushing a seekable input stream, so the
       semantics of fpurge are now appropriate.  */
  #if HAVE_FPURGE
!   {
!     off_t pos = ftello (stream);
! 
!     result = fpurge (stream);
!     if (result == 0)
!       {
!       if (lseek (fileno (stream), pos, SEEK_SET) == -1)
!         result = EOF;
!       }
!   }
  #elif HAVE___FPURGE
    /* __fpurge has no return value, and on Solaris, we can't even trust
       errno.  So assume it succeeds.  */


2) fseek() is heavily optimized: fseeko (fp, pos, SEEK_SET) will position
   the file descriptor to   pos & ~fp->_blksize  and then read one buffer,
   [or if   pos   is inside the current buffer, optimize even more: just
   change some pointers and counters, without accessing the file descriptor],
   unless
     - fp is not seekable, or
     - fp is open for writing (__SWR | __SRW), or
     - fp is unbuffered (__SNBF), or
     - fp has an unusual block size set through setvbuf (__SNPT).
   If your fflush or fseek was to invoke setvbuf, it's hard to keep programs
   working that use setvbuf as well.

   A solution might be to make a wrapper around fseek() roughly like this:

     rpl_fseek (...)
     {
       if (fp is not open for writing
           && fp's buffer is empty, like after fpurge)
         perform just an lseek
       else
         fseek (...);
     }

   The primitives for "fp is not open for writing" can be written in the
   same spirit as the 'fseterr' and 'fpending' modules.

Bruno





reply via email to

[Prev in Thread] Current Thread [Next in Thread]