This is the mail archive of the newlib@sourceware.org mailing list for the newlib 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] Introduce _STDIO_BSD_SEMANTICS


Hi,

following a discussion on the Cygwin mailing list(*), I applied the
below patch.  It introduces a new macro, _STDIO_BSD_SEMANTICS, with the
following property:

  In 2006, a patch has been introduced in newlib, which changed the
  semantics of the fclose and exit calls.
 
  BSD semantics, as followed by all BSD systems, Glibc, and by newlib up
  to 2006, are so that on fclose and exit, FILE streams are flushed (and
  thus the underlying file descriptor seeked!) only if the stream has
  been written to.

  POSIX semantics, as followed by Solaris and newlib since 2006,  are
  so that on fclose and exit, FILE streams are flushed (and thus seeked)
  unconditionally, even for read-only streams.

This subtil difference has interesting side-effects, as soon as
processes have forked or spawned child processes which inherited a
stream read by the parent.  Consider these two scenarios as examples:

  Input file foo.txt:

    aaaaaaa
    bbbbbbb
    ccccccc

  Example 1 (pseudo code):

    fp = fopen ("foo.txt", "r");
    while (fgets (buf, fp)) {
      fprintf (stderr, "%s %ld\n", buf, lseek(fileno(fp), 0, SEEK_CUR));
      switch (fork ()) {
      case CHILD:
        exit (0);
      case PARENT:
      	wait ();
	break;
      }
    }

  Output under BSD sematics:

    aaaaaaa 24
    bbbbbbb 24
    ccccccc 24

  Output under POSIX semantics:

    aaaaaaa 24
    bbbbbbb 8
    ccccccc 0
    aaaaaaa 24
    bbbbbbb 8
    ccccccc 0
    aaaaaaa 24
    bbbbbbb 8
    ccccccc 0
    [...ad infinitum...]

  Example 2:

    sh$ { sed -n 1q; sed -n 1q; cat; } < foo.txt

  Output under BSD semantics:

    <nothing>

  Output under POSIX semantics:

    ccccccc

So my patch now introduces the _STDIO_BSD_SEMANTICS flag.  If you define
it for your target (for instance, in sys/config.h), you get BSD
semantics, while, as long as _STDIO_BSD_SEMANTICS is undefined, your
target sticks to POSIX semantics.


Corinna

(*) http://cygwin.com/ml/cygwin/2014-01/threads.html#00110


        Introduce _STDIO_BSD_SEMANTICS flag to switch fclose/exit file flushing
        semantics from POSIX to BSD.
        * libc/stdio/fclose.c (_fclose_r): Conditionalize file flushing on
        _STDIO_BSD_SEMANTICS.  Call __sflush_r rather than _fflush_r.  Add
        comment.
        * libc/stdio/fflush.c (__sflushw_r): New function, only available
        if _STDIO_BSD_SEMANTICS is defined.
        * libc/stdio/findfp.c (_cleanup_r): Call _fwalk_reent rather than
        _fwalk.  Conditionalize cleanup function call on _STDIO_BSD_SEMANTICS.
        Add comments.  Add FIXME.
        * libc/stdio/local.h (__sflushw_r): Declare if _STDIO_BSD_SEMANTICS is
        defined.


Index: libc/stdio/fclose.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio/fclose.c,v
retrieving revision 1.18
diff -u -p -r1.18 fclose.c
--- libc/stdio/fclose.c	26 Mar 2013 16:07:55 -0000	1.18
+++ libc/stdio/fclose.c	17 Jan 2014 10:50:18 -0000
@@ -92,10 +92,15 @@ _DEFUN(_fclose_r, (rptr, fp),
 #endif
       return (0);
     }
-  /* Unconditionally flush to allow special handling for seekable read
-     files to reposition file to last byte processed as opposed to
-     last byte read ahead into the buffer.  */
-  r = _fflush_r (rptr, fp);
+#ifdef _STDIO_BSD_SEMANTICS
+  /* BSD and Glibc systems only flush streams which have been written to. */
+  r = (fp->_flags & __SWR) ? __sflush_r (rptr, fp) : 0;
+#else
+  /* Follow POSIX semantics exactly.  Unconditionally flush to allow
+     special handling for seekable read files to reposition file to last
+     byte processed as opposed to last byte read ahead into the buffer. */
+  r = __sflush_r (rptr, fp);
+#endif
   if (fp->_close != NULL && fp->_close (rptr, fp->_cookie) < 0)
     r = EOF;
   if (fp->_flags & __SMBF)
Index: libc/stdio/fflush.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio/fflush.c,v
retrieving revision 1.19
diff -u -p -r1.19 fflush.c
--- libc/stdio/fflush.c	23 Oct 2013 10:04:43 -0000	1.19
+++ libc/stdio/fflush.c	17 Jan 2014 10:50:18 -0000
@@ -204,6 +204,19 @@ _DEFUN(__sflush_r, (ptr, fp),
   return 0;
 }
 
+#ifdef _STDIO_BSD_SEMANTICS
+/* Called from _cleanup_r.  At exit time, we don't need file locking,
+   and we don't want to move the underlying file pointer unless we're
+   writing. */
+int
+_DEFUN(__sflushw_r, (ptr, fp),
+       struct _reent *ptr _AND
+       register FILE *fp)
+{
+  return (fp->_flags & __SWR) ?  __sflush_r (ptr, fp) : 0;
+}
+#endif
+
 int
 _DEFUN(_fflush_r, (ptr, fp),
        struct _reent *ptr _AND
Index: libc/stdio/findfp.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio/findfp.c,v
retrieving revision 1.26
diff -u -p -r1.26 findfp.c
--- libc/stdio/findfp.c	25 Apr 2013 15:29:19 -0000	1.26
+++ libc/stdio/findfp.c	17 Jan 2014 10:50:18 -0000
@@ -170,8 +170,17 @@ _VOID
 _DEFUN(_cleanup_r, (ptr),
        struct _reent *ptr)
 {
-  _CAST_VOID _fwalk(ptr, fclose);
-  /* _CAST_VOID _fwalk (ptr, fflush); */	/* `cheating' */
+#ifdef _STDIO_BSD_SEMANTICS
+  /* BSD and Glibc systems only flush streams which have been written to
+     at exit time.  Calling flush rather than close for speed, as on
+     the aforementioned systems. */
+  _CAST_VOID _fwalk_reent (ptr, __sflushw_r);
+#else
+  /* Otherwise close files and flush read streams, too.
+     FIXME: Do we really have to call fclose rather than fflush for
+     RTOS compatibility? */
+  _CAST_VOID _fwalk_reent (ptr, _fclose_r);
+#endif
 }
 
 #ifndef _REENT_ONLY
Index: libc/stdio/local.h
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio/local.h,v
retrieving revision 1.38
diff -u -p -r1.38 local.h
--- libc/stdio/local.h	23 Oct 2013 10:04:43 -0000	1.38
+++ libc/stdio/local.h	17 Jan 2014 10:50:18 -0000
@@ -147,6 +147,9 @@ int	      _EXFUN(_svfiwprintf_r,(struct 
 extern FILE  *_EXFUN(__sfp,(struct _reent *));
 extern int    _EXFUN(__sflags,(struct _reent *,_CONST char*, int*));
 extern int    _EXFUN(__sflush_r,(struct _reent *,FILE *));
+#ifdef _STDIO_BSD_SEMANTICS
+extern int    _EXFUN(__sflushw_r,(struct _reent *,FILE *));
+#endif
 extern int    _EXFUN(__srefill_r,(struct _reent *,FILE *));
 extern _READ_WRITE_RETURN_TYPE _EXFUN(__sread,(struct _reent *, void *, char *,
 					       _READ_WRITE_BUFSIZE_TYPE));



-- 
Corinna Vinschen
Cygwin Maintainer
Red Hat

Attachment: pgpMC2_0SUxsG.pgp
Description: PGP signature


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