Re: [PATCH] prevent retries on fclose/fflush after write errors

2013-02-24 Thread Denys Vlasenko
On Monday 18 February 2013 20:58, Bernhard Reutner-Fischer wrote:
 On 25 March 2012 07:54, Mike Frysinger vap...@gentoo.org wrote:
  fixed the style  pushed.  thanks all!  it's nice we have people versed in
  esoteric low level aspects nowadays.
 
 hmz, revisiting..
 To recap:
 
 On 7 February 2011 02:41, Denys Vlasenko vda.li...@googlemail.com wrote:
  Currently, uclibc retains buffered data on stdio write errors,
  and subsequent fclose and fflush will try to write it out again
  (in most cases, in vain).
 
  Which results in something like this:
 
  On Wednesday 26 January 2011 13:21, Baruch Siach wrote:
  Hi busybox list,
 
  I'm running the following command under strace (thanks Rob):
 
  echo 56  /sys/class/gpio/export
 
  and I see the following output:
 
  write(1, 56\n, 3) = -1 EBUSY (Device or resource 
  busy)
  write(1, 5, 1)= 1
 
  The first EBUSY is OK, since GPIO 56 is already requested. But the second
  write() attempt seems strange, and leads to an unwanted outcome. GPIO 5 
  gets
  exported.
 
 
  This patch prevents that.
 
 This rather sounds to me that this second write with an odd length is wrong, 
 no?

 IIUC the patch (867bac0c) that went in for this issue is causing
 https://bugs.uclibc.org/5156 (fclose and fflush do not report write failures)
 
 I am attaching denys.c, i think this is the testcase you had in mind
 in your patch that Mike applied as
 867bac0c750401d2f429ad6bb066498c3b8b35c1
 The attached fulltest.c is from above mentioned PR5156.
 Also attached is a patch that seems to cure PR5156 (the hunk against
 _wcommit.c is your rephrased patch cited below, not needed for 5156
 though) and that basically reverts your 867bac0c.
 With this patch we would get:
 $ ./denys_uc  /dev/null
 Hi there 1
 Hi there 2
 $ ./denys_uc 2 /dev/null
 $ ./denys_glibc  /dev/null
 Hi there 1
 Hi there 2
 $ ./denys_glibc 2 /dev/null
 $ ./fulltest_glibc
 fwrite: x=4, errno=25
 fflush: y=-1, errno=28
 fputc 1: x=88, errno=25
 fflush: y=-1, errno=28
 fputc 2: x=88, errno=25
 fclose: y=-1, errno=28
 # the ENOTYPEWRITER i dislike
 $ ./fulltest
 fwrite: x=4, errno=0
 fflush: y=-1, errno=28
 fputc 1: x=88, errno=28
 fflush: y=-1, errno=28
 fputc 2: x=88, errno=28
 fclose: y=-1, errno=28
 so 5156 would be fixed, we'd diverge from glibc in the type-writer
 errno (which is imo ok) and (since we fully buffer fwrite) do not
 errno the fwrite.

Testcases? Good! Please put them into test/* when you're done.


 I guess it would not fix your (line-buffered, i assume?) gpio echo, would it?

I don't know whether it will fix that. I don't have the testcase handy.

In my testing after this patch uclibc drops all output after error occurs.

I have a test program which sets stdout to nonblocking mode, writes lines until
printf fails, then resets stdouty to blocking mode, does fflush(NULL),
and prints last printf result and count of lines.

I run it like this:   ./a.out | { sleep 1; cat; }

Before your patch, the result was:
Hi there 1
Hi there 2
Hi there 3
...
Hi there 02644
Hi there 02645
Hi there 0
n:-1
Bye 02647


After this patch, output just ends:
...
Hi there 02590
Hi there 02591
Hi there 02592 ---no newline char printed here

strace of the above:
...
18:39:29.777493 write(1, \nHi there 02539\nHi there 02540\nHi there 
02541\nHi there 02542\nHi there 02543\nHi ..., 1022) = 1022
18:39:29.777550 write(1, 2592, 4) = 4
18:39:29.777640 write(1, \nHi there 02593\nHi there 02594\nHi there 
02595\nHi there 02596\nHi there 02597\nHi ..., 1022) = -1 EAGAIN 
(Resource temporarily u
navailable)
18:39:29.02 fcntl(1, F_GETFL)   = 0x801 (flags O_WRONLY|O_NONBLOCK)
18:39:29.59 fcntl(1, F_SETFL, O_WRONLY) = 0
18:39:29.777814 _exit(0)= ?
18:39:29.777870 +++ exited with 0 +++

IOW: EAGAIN become a fatal, data-gobbling error,
stream will remain inoperative even after error goes away (!).
The final printf in my program (see source) just didn't do anything.

glibc does this:
...
Hi there 03449
Hi th
n:-1
Bye 03666

As you see, glibc doesn't kill the stream on EAGAIN.



I think this part of the patch is wrong:

-   } else {
+   } else /* if (errno != EINTR  errno != EAGAIN) */ {
.
__STDIO_STREAM_SET_ERROR(stream);
-
+#if 0
/* We buffer data on transient errors, but discard it
 * on hard ones. Example of a hard error:
 *
@@ -81,6 +81,7 @@ size_t attribute_hidden __stdio_WRITE(register FILE *stream,
/* do we have other soft errors? */
break;
}
+#endif
 #ifdef __STDIO_BUFFERS
stodo = __STDIO_STREAM_


it simple drops special handling of EAGAIN.


The test program follows.
-- 
vda

#include unistd.h
#include stdio.h
#include errno.h

Re: [PATCH] prevent retries on fclose/fflush after write errors

2013-02-18 Thread Bernhard Reutner-Fischer
On 25 March 2012 07:54, Mike Frysinger vap...@gentoo.org wrote:
 fixed the style  pushed.  thanks all!  it's nice we have people versed in
 esoteric low level aspects nowadays.

hmz, revisiting..
To recap:

On 7 February 2011 02:41, Denys Vlasenko vda.li...@googlemail.com wrote:
 Currently, uclibc retains buffered data on stdio write errors,
 and subsequent fclose and fflush will try to write it out again
 (in most cases, in vain).

 Which results in something like this:

 On Wednesday 26 January 2011 13:21, Baruch Siach wrote:
 Hi busybox list,

 I'm running the following command under strace (thanks Rob):

 echo 56  /sys/class/gpio/export

 and I see the following output:

 write(1, 56\n, 3) = -1 EBUSY (Device or resource busy)
 write(1, 5, 1)= 1

 The first EBUSY is OK, since GPIO 56 is already requested. But the second
 write() attempt seems strange, and leads to an unwanted outcome. GPIO 5 gets
 exported.


 This patch prevents that.

This rather sounds to me that this second write with an odd length is wrong, no?
IIUC the patch (867bac0c) that went in for this issue is causing
https://bugs.uclibc.org/5156 (fclose and fflush do not report write failures)

I am attaching denys.c, i think this is the testcase you had in mind
in your patch that Mike applied as
867bac0c750401d2f429ad6bb066498c3b8b35c1
The attached fulltest.c is from above mentioned PR5156.
Also attached is a patch that seems to cure PR5156 (the hunk against
_wcommit.c is your rephrased patch cited below, not needed for 5156
though) and that basically reverts your 867bac0c.
With this patch we would get:
$ ./denys_uc  /dev/null
Hi there 1
Hi there 2
$ ./denys_uc 2 /dev/null
$ ./denys_glibc  /dev/null
Hi there 1
Hi there 2
$ ./denys_glibc 2 /dev/null
$ ./fulltest_glibc
fwrite: x=4, errno=25
fflush: y=-1, errno=28
fputc 1: x=88, errno=25
fflush: y=-1, errno=28
fputc 2: x=88, errno=25
fclose: y=-1, errno=28
# the ENOTYPEWRITER i dislike
$ ./fulltest
fwrite: x=4, errno=0
fflush: y=-1, errno=28
fputc 1: x=88, errno=28
fflush: y=-1, errno=28
fputc 2: x=88, errno=28
fclose: y=-1, errno=28
so 5156 would be fixed, we'd diverge from glibc in the type-writer
errno (which is imo ok) and (since we fully buffer fwrite) do not
errno the fwrite.
I guess it would not fix your (line-buffered, i assume?) gpio echo, would it?

 --
 vda

 diff -d -urpN uClibc.0/libc/stdio/_wcommit.c uClibc.1/libc/stdio/_wcommit.c
 --- uClibc.0/libc/stdio/_wcommit.c  2011-02-07 00:04:34.0 +0100
 +++ uClibc.1/libc/stdio/_wcommit.c  2011-02-07 00:55:24.0 +0100
 @@ -20,7 +20,18 @@ size_t attribute_hidden __stdio_wcommit(

 __STDIO_STREAM_VALIDATE(stream);

 -   if ((bufsize = __STDIO_STREAM_BUFFER_WUSED(stream)) != 0) {
 +   /* Note: we do not write anything if write error has been detected.
 +* Otherwise, stdio user has no way to prevent retries after
 +* failed write - and some users do want to not have any retries!
 +* IOW: if write errored out, neither fflush nor fclose should
 +* try to write buffered data.
 +* clearerr may be used to enable retry if needed.
 +*/
 +
 +   bufsize = __STDIO_STREAM_BUFFER_WUSED(stream);
 +   if (bufsize != 0
 + !(stream-__modeflags  __FLAG_ERROR)
 +   ) {
 stream-__bufpos = stream-__bufstart;
 __stdio_WRITE(stream, stream-__bufstart, bufsize);
 }
___
uClibc mailing list
uClibc@uclibc.org
http://lists.busybox.net/mailman/listinfo/uclibc


Re: [PATCH] prevent retries on fclose/fflush after write errors

2013-02-18 Thread Bernhard Reutner-Fischer
attaching..

On 18 February 2013 20:58, Bernhard Reutner-Fischer
rep.dot@gmail.com wrote:
 On 25 March 2012 07:54, Mike Frysinger vap...@gentoo.org wrote:
 fixed the style  pushed.  thanks all!  it's nice we have people versed in
 esoteric low level aspects nowadays.

 hmz, revisiting..
 To recap:

 On 7 February 2011 02:41, Denys Vlasenko vda.li...@googlemail.com wrote:
 Currently, uclibc retains buffered data on stdio write errors,
 and subsequent fclose and fflush will try to write it out again
 (in most cases, in vain).

 Which results in something like this:

 On Wednesday 26 January 2011 13:21, Baruch Siach wrote:
 Hi busybox list,

 I'm running the following command under strace (thanks Rob):

 echo 56  /sys/class/gpio/export

 and I see the following output:

 write(1, 56\n, 3) = -1 EBUSY (Device or resource busy)
 write(1, 5, 1)= 1

 The first EBUSY is OK, since GPIO 56 is already requested. But the second
 write() attempt seems strange, and leads to an unwanted outcome. GPIO 5 gets
 exported.


 This patch prevents that.

 This rather sounds to me that this second write with an odd length is wrong, 
 no?
 IIUC the patch (867bac0c) that went in for this issue is causing
 https://bugs.uclibc.org/5156 (fclose and fflush do not report write failures)

 I am attaching denys.c, i think this is the testcase you had in mind
 in your patch that Mike applied as
 867bac0c750401d2f429ad6bb066498c3b8b35c1
 The attached fulltest.c is from above mentioned PR5156.
 Also attached is a patch that seems to cure PR5156 (the hunk against
 _wcommit.c is your rephrased patch cited below, not needed for 5156
 though) and that basically reverts your 867bac0c.
 With this patch we would get:
 $ ./denys_uc  /dev/null
 Hi there 1
 Hi there 2
 $ ./denys_uc 2 /dev/null
 $ ./denys_glibc  /dev/null
 Hi there 1
 Hi there 2
 $ ./denys_glibc 2 /dev/null
 $ ./fulltest_glibc
 fwrite: x=4, errno=25
 fflush: y=-1, errno=28
 fputc 1: x=88, errno=25
 fflush: y=-1, errno=28
 fputc 2: x=88, errno=25
 fclose: y=-1, errno=28
 # the ENOTYPEWRITER i dislike
 $ ./fulltest
 fwrite: x=4, errno=0
 fflush: y=-1, errno=28
 fputc 1: x=88, errno=28
 fflush: y=-1, errno=28
 fputc 2: x=88, errno=28
 fclose: y=-1, errno=28
 so 5156 would be fixed, we'd diverge from glibc in the type-writer
 errno (which is imo ok) and (since we fully buffer fwrite) do not
 errno the fwrite.
 I guess it would not fix your (line-buffered, i assume?) gpio echo, would it?

 --
 vda

 diff -d -urpN uClibc.0/libc/stdio/_wcommit.c uClibc.1/libc/stdio/_wcommit.c
 --- uClibc.0/libc/stdio/_wcommit.c  2011-02-07 00:04:34.0 +0100
 +++ uClibc.1/libc/stdio/_wcommit.c  2011-02-07 00:55:24.0 +0100
 @@ -20,7 +20,18 @@ size_t attribute_hidden __stdio_wcommit(

 __STDIO_STREAM_VALIDATE(stream);

 -   if ((bufsize = __STDIO_STREAM_BUFFER_WUSED(stream)) != 0) {
 +   /* Note: we do not write anything if write error has been detected.
 +* Otherwise, stdio user has no way to prevent retries after
 +* failed write - and some users do want to not have any retries!
 +* IOW: if write errored out, neither fflush nor fclose should
 +* try to write buffered data.
 +* clearerr may be used to enable retry if needed.
 +*/
 +
 +   bufsize = __STDIO_STREAM_BUFFER_WUSED(stream);
 +   if (bufsize != 0
 + !(stream-__modeflags  __FLAG_ERROR)
 +   ) {
 stream-__bufpos = stream-__bufstart;
 __stdio_WRITE(stream, stream-__bufstart, bufsize);
 }
#include unistd.h
#include stdio.h
#include errno.h
#include assert.h

int main(void) {
	int i;
	int oldfd = fileno(stderr);
	int newfd = fileno(stdout);

	i = close(newfd);
	assert(i == 0);
	i = printf(Hi there 1\n);
	assert(i == 11);
	i = ferror(stdout);
	assert(i == 0);
	i = dup2(oldfd, newfd);
	assert(i == newfd);
	i = printf(Hi there 2\n);
	assert(i == 11);
	return 0;
}
#include assert.h
#include stdio.h
#include stdlib.h
#include string.h
#include errno.h

int
main (int argc, char **argv)
{
  FILE *f;
  int x, y;
  char str[1024];
  memset (str, 'X', sizeof str);

  /* subcase 0 */
  f = fopen (/dev/full, w);
  assert (f);
  x = fwrite (str, 1024/4, 4, f);
  printf(fwrite: x=%d, errno=%d\n, x, errno);
  y = fflush (f);
  printf(fflush: y=%d, errno=%d\n, y, errno);
  assert (x == EOF || y == EOF);
  fclose (f);


  /* subcase 1 */
  f = fopen (/dev/full, w);
  assert (f);
  x = fputc ('X', f);
  printf(fputc 1: x=%d, errno=%d\n, x, errno);
  y = fflush (f);
  printf(fflush: y=%d, errno=%d\n, y, errno);
  assert (x == EOF || y == EOF);
  fclose (f);

  /* subcase 2 */
  f = fopen (/dev/full, w);
  assert (f);
  x = fputc ('X', f);
  printf(fputc 2: x=%d, errno=%d\n, x, errno);
  y = fclose (f);
  printf(fclose: y=%d, errno=%d\n, y, errno);
  assert (x == EOF || y == EOF);

  return EXIT_SUCCESS;
}


uClibc-redo-867bac0c750401d2f429ad6bb066498c3b8b35c1.00.patch
Description: 

Re: [PATCH] prevent retries on fclose/fflush after write errors

2012-03-24 Thread Mike Frysinger
fixed the style  pushed.  thanks all!  it's nice we have people versed in 
esoteric low level aspects nowadays.
-mike


signature.asc
Description: This is a digitally signed message part.
___
uClibc mailing list
uClibc@uclibc.org
http://lists.busybox.net/mailman/listinfo/uclibc

Re: [PATCH] prevent retries on fclose/fflush after write errors

2012-03-23 Thread Michael Deutschmann
On Wed, 14 Mar 2012, Rich Felker wrote:
 It was cited in Worse is Better, yes, but I don't entirely believe
 the anecdote. SA_RESTART semantics are no harder to implement; it's
 just a matter of whether you save the address of the syscall
 instruction or the instruction immediately after it when invoking a
 signal handler.

Usually the address instruction immediately after will already be on the
stack, or some sort of task structure, as part of the normal syscall
process that would be followed in the absence of signals.

Now, adjusting the saved instruction pointer would not be hard in machine
code.  Generally, the saved user IP is sitting somewhere in the kernel
stack a predictable distance above the return address for the kernel
function implementing the call, like a hidden extra argument.  But access
to such context isn't something C compilers are good at, and the stack
offset and syscall opcode length must be customized for each processor
family.

The ancient worse-is-better Unix programmers probably decided to just
foreclose on syscalls doing anything to the userspace registers (aside
from the one used to return results).  This made the assembly glue
joining a CPU-agnostic C kernel to a specific machine as simple as
possible, and made EINTR the only acceptable way.

 It can be solved (albeit in an ugly way) by having the signal handler
 re-arm the alarm with exponential falloff in delay (in case the system
 is so loaded that it can't return from the signal handler before
 another timer expiration happens).

Yuck.  That's a lousy quality of implemantion, and isn't even adequate
for probing whether a system implements EINTR.

 Even if your approach is preferable to users, I don't think it's
 conformant, since POSIX specifies the EINTR error for fgetc. Since all

That may be just tolerance for a lazy stdio that doesn't work any harder
than it needs to.  Certainly no one disputes a stdio is *allowed* to treat
EINTR same as EIO.  The question is whether it *must*.

 Michael Deutschmann mich...@talamasca.ocis.net
___
uClibc mailing list
uClibc@uclibc.org
http://lists.busybox.net/mailman/listinfo/uclibc


Re: [PATCH] prevent retries on fclose/fflush after write errors

2012-03-14 Thread Johannes Stezenbach
On Tue, Mar 13, 2012 at 10:58:33AM -0400, Rich Felker wrote:
 On Tue, Mar 13, 2012 at 10:30:10AM +0100, Laurent Bercot wrote:
 
   Why not simply let the user set SA_RESTART in the sigaction() call?
  see http://www.skarnet.org/software/skalibs/libstddjb/safewrappers.html
 
 I know of no modern system where this kind of bogus EINTR happens
 (SIGSTOP, etc.). Even the proprietary unices fixed it before Linux
 did, but they've all been fixed for a long time now. I agree the
 standard should be more explicit on this; failure to be explicit, if
 you interpret it literally, makes interrupting signals unusable since
 you have to wrap all your syscalls with loops and make them behave as
 if the signal was a restarting one..

FWIW, Michael Kerrisk's book The Linux Programming Interface
lists a number of syscalls which can return EINTR after resume
from SIGSTOP.  Normal read() is not one of them, but e.g. read() from
inotify fd is.  I would also expect that some character devices
do not implement restarting for read() and write(), if just
because ERESTARTSYS etc. are not sufficiently documented.

Also, the system calls for which SA_RESTART is effective seems
to change over time, e.g. before 2.6.22 futex(),
sem_wait and sem_timedwait() did not observe SA_RESTART.
(There's about a page listing various syscall's behaviour
with SA_RESTART in TLPI book.)


Johannes
___
uClibc mailing list
uClibc@uclibc.org
http://lists.busybox.net/mailman/listinfo/uclibc


Re: [PATCH] prevent retries on fclose/fflush after write errors

2012-03-14 Thread Michael Deutschmann
On Tue, 13 Mar 2012, Rich Felker wrote:
 I would consider this a flaw in the standard since it largely prevents
 using EINTR in any useful way.

EINTR wasn't invented to be useful, it was invented because it was easier
to implement in pre-sigaction() SysV kernels than SA_RESTART semantics.
Known as the PCLSR problem, it is an often cited example of the Worse
is Better design philosophy at work.

 I was assuming the old standard idiom of installing a do-nothing signal
 handler (without SA_RESTART) for SIGALRM so that fgets would return with
 an error and the program could proceed.

That's a broken idiom, since if the signal should arrive just one opcode
before the read syscall begins, it will be ignored.  If you need reliable
signal interruption, you must use sigsuspend() or longjmp out of the
handler.

It's also the only possible use of a cleared SA_RESTART, so it's crazy not
to set the flag all the time.  That we have a SA_RESTART flag at all, is
just a measure so that old SysV programs abusing the design flaw break
occasionally instead of often.

One historical note:

Circa 2000, I was actively reading glibc's bugs list and trying to help
out.  Someone posted a bug report (libc/1174 in the old GNATS system)
citing this very issue, and I suggested a patch to restart after EINTR
within stdio -- since any deliberate use of interruption would involve a
race condition.

Ulrich Drepper denied it, on the grounds that:
) But this is not correct.  You must be able to set an alarm() and
) terminate a blocked fwrite() code.  This is required and tested by all
) kinds of standard test suites.

Although that exchange eventually had one productive result -- the node
Error Recovery in the glibc manual, which I basically wrote.

Sounds like in the intervening decade, glibc may have come around to my
thinking

 Michael Deutschmann mich...@talamasca.ocis.net
___
uClibc mailing list
uClibc@uclibc.org
http://lists.busybox.net/mailman/listinfo/uclibc


Re: [PATCH] prevent retries on fclose/fflush after write errors

2012-03-14 Thread Mike Frysinger
On Monday 12 March 2012 01:27:08 Kevin Cernekee wrote:
 + if (errno != EINTR
 +  errno != EAGAIN
 + /* do we have other soft errors? */
 + ) {
 + break;

stylewise, this break is missing a tab too :p

otherwise, this looks good to go, no one has any complaints with it, so should 
be good to merge ...
-mike


signature.asc
Description: This is a digitally signed message part.
___
uClibc mailing list
uClibc@uclibc.org
http://lists.busybox.net/mailman/listinfo/uclibc

Re: [PATCH] prevent retries on fclose/fflush after write errors

2012-03-14 Thread Rich Felker
On Wed, Mar 14, 2012 at 02:26:06PM +0100, Johannes Stezenbach wrote:
 On Tue, Mar 13, 2012 at 10:58:33AM -0400, Rich Felker wrote:
  On Tue, Mar 13, 2012 at 10:30:10AM +0100, Laurent Bercot wrote:
  
Why not simply let the user set SA_RESTART in the sigaction() call?
   see http://www.skarnet.org/software/skalibs/libstddjb/safewrappers.html
  
  I know of no modern system where this kind of bogus EINTR happens
  (SIGSTOP, etc.). Even the proprietary unices fixed it before Linux
  did, but they've all been fixed for a long time now. I agree the
  standard should be more explicit on this; failure to be explicit, if
  you interpret it literally, makes interrupting signals unusable since
  you have to wrap all your syscalls with loops and make them behave as
  if the signal was a restarting one..
 
 FWIW, Michael Kerrisk's book The Linux Programming Interface
 lists a number of syscalls which can return EINTR after resume
 from SIGSTOP.

It's outdated. See man 7 signal for details on what has/hasn't been
fixed. The only ones still broken are all in the timed wait family,
for which isn't not that big a deal to return early anyway since the
caller expects that a timed wait operation might fail with a timeout
and already has to deal with this error case.

  Normal read() is not one of them, but e.g. read() from
 inotify fd is.

While this is broken in principle, inotify is enough of an oddball
(and only really usable paired with select/poll anyway) that it
probably doesn't matter.

 I would also expect that some character devices
 do not implement restarting for read() and write(), if just
 because ERESTARTSYS etc. are not sufficiently documented.

I'm not aware of any such issues, at least not with the devices normal
user apps would interface with. The main type, terminals, are not
buggy in this regard (but are buggy in regard to readv/writev in a
different manner).

It's actually really frustrating that Linux exposes the potential
brokenness of each underlying driver to the application. The read
syscall itself should be enforcing POSIX conformance regardless of how
the underlying driver behaves.

 Also, the system calls for which SA_RESTART is effective seems
 to change over time, e.g. before 2.6.22 futex(),
 sem_wait and sem_timedwait() did not observe SA_RESTART.
 (There's about a page listing various syscall's behaviour
 with SA_RESTART in TLPI book.)

Yes, that was a serious bug. Thankfully it's been fixed, and there are
enough other relatively important fixes around the same time that it's
a really bad idea to be using such an old kernel for applications that
use threads.

Rich
___
uClibc mailing list
uClibc@uclibc.org
http://lists.busybox.net/mailman/listinfo/uclibc


Re: [PATCH] prevent retries on fclose/fflush after write errors

2012-03-13 Thread Rich Felker
On Tue, Mar 13, 2012 at 07:16:54AM +, u-uclibc-q...@aetey.se wrote:
 On Tue, Mar 13, 2012 at 01:58:49AM -0400, Rich Felker wrote:
  On Tue, Mar 13, 2012 at 01:41:01AM -0400, Mike Frysinger wrote:
int __filedes;
+   int __errno_value;
 
   pretty sure this breaks ABI.  i know we aren't completely strict on this, 
   but 
   it's something we should avoid if possible.
  
  How so? Application code should not be touching the internals of
  FILE...
 
 You are right Rich but it seems you are thinking of API while this change
 breaks ABI.

If it does, I still don't see how it could. Applications cannot
declare objects of type FILE, only FILE *. Short of some macros that
poke at the early members of the structure (getc/putc macros), it's
purely an opaque type, so changes to its size or layout (beyond said
early members) should not break ABI. If you claim it does, please
explain how you think it does, because the rest of us are missing that
issue..

Rich
___
uClibc mailing list
uClibc@uclibc.org
http://lists.busybox.net/mailman/listinfo/uclibc


Re: [PATCH] prevent retries on fclose/fflush after write errors

2012-03-13 Thread Rich Felker
On Tue, Mar 13, 2012 at 10:30:10AM +0100, Laurent Bercot wrote:
  Note that I'm claiming the whole safe_read/safe_write idiom is
  wrong, and a throwback to the pre-sigaction SysV era when signal() was
  the only way to install a signal handler and it gave you
  non-restarting semantics. The idea of an interrupting signal, when set
  intentionally by a modern application using sigaction, is that EINTR
  should be treated as a (usually permanent/unrecoverable) failure on
  blocked in-progress IO operations.
 
  Hi Rich,
 
  I'm not pronouncing on stdio, since stdio doesn't really mix with
 asynchronous event loops anyway; but in an event-driven program that
 reacts to signals as well as fd events or timeouts, signals can
 arrive at any time and should be handled by the application at the
 same level as any other event, in a normal context, *not* right when
 they arrive in an interrupt context. (Think pselect(), or the self-pipe
 trick.)

I agree that interrupting signals are not very useful for an
event-driven application. This is not their intended usage case.

  In this case, it is absolutely necessary to protect every read() and
 write() operation, as well as any interruptible system call, against
 EINTR, because EINTR is not reporting a failure, it is only reporting
 the arrival of a signal at an inconvenient time.

EINTR is basically reporting that the user hit Ctrl+C and the
application wants the library routine that was in progress to return
with an error rather than asynchronously exiting, probably because it
has unwritten state that can't be accessed asynchronously for saving.

There is no reason to protect reads against EINTR because EINTR
cannot happen unless the application specifically chooses for it to
happen (by installing a non-restarting signal handler). EINTR does not
just randomly happen.

  This protection can be done at the user level, but there is nothing wrong

My claim is that code doing such protection is wrong and harmful to
begin with.

  Why not simply let the user set SA_RESTART in the sigaction() call?
 see http://www.skarnet.org/software/skalibs/libstddjb/safewrappers.html

I know of no modern system where this kind of bogus EINTR happens
(SIGSTOP, etc.). Even the proprietary unices fixed it before Linux
did, but they've all been fixed for a long time now. I agree the
standard should be more explicit on this; failure to be explicit, if
you interpret it literally, makes interrupting signals unusable since
you have to wrap all your syscalls with loops and make them behave as
if the signal was a restarting one..

I think the difference in opinion about EINTR comes from two different
ideological camps: one which believes the Worse is Better story that
the very existence of EINTR was a bug in early Unix systems, and
another which believes EINTR was/is a feature to allow a program
interrupted during a blocked operation by a (usually user-generated)
signal to terminate or return to an initial state cleanly without
breaking the rules of async signal safety, discarding whatever
intermediate work it was doing.

Think of programs that do something like:
alarm(1);
fgets(buf, sizeof buf, f);

Rich
___
uClibc mailing list
uClibc@uclibc.org
http://lists.busybox.net/mailman/listinfo/uclibc


Re: [PATCH] prevent retries on fclose/fflush after write errors

2012-03-13 Thread Rich Felker
On Tue, Mar 13, 2012 at 01:46:39AM -0400, Mike Frysinger wrote:
 treating EINTR/EAGAIN as unrecoverable is bad behavior for an app.  there are 
 valid ways an app could receive either signal and have it be normal behavior.

Receiving a signal does not result in EINTR. Running a signal handler
that was installed (intentionally) without SA_RESTART is what causes
EINTR.

 having that handling be done in uClibc is not required by POSIX, but it's 
 better imo for uClibc to carry a little bit more code there to provide better 
 reliability to higher layers rather than forcing every userspace app to 
 implement their own retry-on-eagain macros.

Retrying on EAGAIN is simply *wrong*. It makes you consume 100% cpu.
If the file descriptor is set as EAGAIN, it means whoever set it up
wants to ensure that blocking does not happen; emulating blocking with
100% cpu load is the worst possible way to handle this situation! For
stdio, EAGAIN must be treated as a hard error.

Rich
___
uClibc mailing list
uClibc@uclibc.org
http://lists.busybox.net/mailman/listinfo/uclibc


Re: [PATCH] prevent retries on fclose/fflush after write errors

2012-03-13 Thread u-uclibc-qs50
Hi Rich,

On Tue, Mar 13, 2012 at 10:36:48AM -0400, Rich Felker wrote:
   On Tue, Mar 13, 2012 at 01:41:01AM -0400, Mike Frysinger wrote:
   int __filedes;
 + int __errno_value;

  You are right Rich but it seems you are thinking of API while this change
  breaks ABI.
 
 If it does, I still don't see how it could. Applications cannot
 declare objects of type FILE, only FILE *. Short of some macros that
 poke at the early members of the structure (getc/putc macros), it's

Applications actually can declare, allocate, copy FILE objects
unless explicitely prohibited by the specification - does it
prohibit this? All I found is a mention that a copy of a FILE object
is unusable at a different address than the original
(http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf page 266
last paragraph).

I can not think of an apparent meaningful reason for copying FILE or
using sizeof(FILE) but this by itself doesn't mean there isn't any.

(sorry for a phrase with three negations...)

That's why I assume that the FILE structure as a whole is a part of the
ABI, despite being opaque.

I may be wrong reading/interpreting specification(s), then please
correct me.

The actual change being discussed may be compatible in practice,
I take your word for this!

 Rich

Regards,
Rune

___
uClibc mailing list
uClibc@uclibc.org
http://lists.busybox.net/mailman/listinfo/uclibc


Re: [PATCH] prevent retries on fclose/fflush after write errors

2012-03-13 Thread Rich Felker
On Tue, Mar 13, 2012 at 04:06:35PM +, u-uclibc-q...@aetey.se wrote:
 Hi Rich,
 
 On Tue, Mar 13, 2012 at 10:36:48AM -0400, Rich Felker wrote:
On Tue, Mar 13, 2012 at 01:41:01AM -0400, Mike Frysinger wrote:
  int __filedes;
  +   int __errno_value;
 
   You are right Rich but it seems you are thinking of API while this change
   breaks ABI.
  
  If it does, I still don't see how it could. Applications cannot
  declare objects of type FILE, only FILE *. Short of some macros that
  poke at the early members of the structure (getc/putc macros), it's
 
 Applications actually can declare, allocate, copy FILE objects
 unless explicitely prohibited by the specification - does it
 prohibit this? All I found is a mention that a copy of a FILE object
 is unusable at a different address than the original
 (http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf page 266
 last paragraph).

Applications presumably can do this, but the only use for doing so
would be to use the object as a buffer of type `char[sizeof(FILE)]`.
It can't be used for any purpose connected with stdio. And being that
the size is very arbitrary, I can't see how you could use it for
anything useful; the only thing you know about `sizeof(FILE)` is that
it's greater than or equal to 1. Presumably it could even have size
SIZE_MAX to prevent applications from declaring objects of type
FILE... :-)

 That's why I assume that the FILE structure as a whole is a part of the
 ABI, despite being opaque.
 
 I may be wrong reading/interpreting specification(s), then please
 correct me.
 
 The actual change being discussed may be compatible in practice,
 I take your word for this!

I believe you may be technically correct, but there's no correct/sane
program that would be affected by this ABI change.

Rich
___
uClibc mailing list
uClibc@uclibc.org
http://lists.busybox.net/mailman/listinfo/uclibc


Re: [PATCH] prevent retries on fclose/fflush after write errors

2012-03-13 Thread Laurent Bercot
 There is no reason to protect reads against EINTR because EINTR
 cannot happen unless the application specifically chooses for it to
 happen (by installing a non-restarting signal handler). EINTR does not
 just randomly happen.

 It can, if you take the standard literally. I agree that you *should*
be able to assume that unblockable signals have SA_RESTART behaviour,
that would simplify Unix programming a whole lot. But as of today, you
can't, and I'd rather be on the safe side.


 My claim is that code doing such protection is wrong and harmful to
 begin with.

 I disagree, because it has its uses. But I think we can agree that it
is wrong to do it *in the libc*. The programmer should have the choice
to handle EINTR himself.


 Think of programs that do something like:
 alarm(1);
 fgets(buf, sizeof buf, f);

 SIGALRM is raised. SIGALRM isn't caught. SIGALRM kills the process,
even if it was blocking on a safe_read() function. Where's the problem?

-- 
 Laurent
___
uClibc mailing list
uClibc@uclibc.org
http://lists.busybox.net/mailman/listinfo/uclibc


Re: [PATCH] prevent retries on fclose/fflush after write errors

2012-03-13 Thread Rich Felker
On Tue, Mar 13, 2012 at 06:59:03PM +0100, Laurent Bercot wrote:
  There is no reason to protect reads against EINTR because EINTR
  cannot happen unless the application specifically chooses for it to
  happen (by installing a non-restarting signal handler). EINTR does not
  just randomly happen.
 
  It can, if you take the standard literally. I agree that you *should*
 be able to assume that unblockable signals have SA_RESTART behaviour,
 that would simplify Unix programming a whole lot. But as of today, you
 can't, and I'd rather be on the safe side.

I'd have to go back and look at the (disorganized) language about it
in the standard, but you may be right about the lack of a strict
requirement. I would consider this a flaw in the standard since it
largely prevents using EINTR in any useful way. There's a similar bug
in the statement of pthread cancellation behavior that makes it so
implementations are allowed (and glibc/uClibc exercise this
allowance!) to leak resources or worse (corrupt fd state) randomly
when cancellation is performed; allowing implementations of such low
quality essentially makes the feature unusable. This should really all
be documented well and submitted as defect reports...

  My claim is that code doing such protection is wrong and harmful to
  begin with.
 
  I disagree, because it has its uses. But I think we can agree that it
 is wrong to do it *in the libc*. The programmer should have the choice
 to handle EINTR himself.

In some places in a program you might know it's essential to complete
the operation and not lose data, in which case you're right, but this
sort of situation will require specific contracts between the callee
and caller about what to do. In general, I feel like the appropriate
response to EINTR in the absence of a contract with the caller is to
assume that when the caller has arranged for EINTR to happen, the
caller wants you to stop when interrupted.

  Think of programs that do something like:
  alarm(1);
  fgets(buf, sizeof buf, f);
 
  SIGALRM is raised. SIGALRM isn't caught. SIGALRM kills the process,
 even if it was blocking on a safe_read() function. Where's the problem?

I was assuming the old standard idiom of installing a do-nothing
signal handler (without SA_RESTART) for SIGALRM so that fgets would
return with an error and the program could proceed.

Rich
___
uClibc mailing list
uClibc@uclibc.org
http://lists.busybox.net/mailman/listinfo/uclibc

Re: [PATCH] prevent retries on fclose/fflush after write errors

2012-03-13 Thread u-uclibc-qs50
On Tue, Mar 13, 2012 at 01:14:12PM -0400, Rich Felker wrote:
 SIZE_MAX to prevent applications from declaring objects of type
 FILE... :-)

:-) I guess you are right and nobody declares them.

 there's no correct/sane
 program that would be affected by this ABI change.

Actually I suspect that stdio macros might use stuff (like __bufpos)
which is located past the proposed new structure member, in which case
existing binaries would become incompatible with a patched library:

  #endif /* __UCLIBC_HAS_WCHAR__ */
 int __filedes;
 +   int __errno_value;
  #ifdef __STDIO_BUFFERS
 unsigned char *__bufstart;  /* pointer to buffer */
 unsigned char *__bufend;/* pointer to 1 past end of buffer */
-  unsigned char *__bufpos;

Rune

___
uClibc mailing list
uClibc@uclibc.org
http://lists.busybox.net/mailman/listinfo/uclibc


Re: [PATCH] prevent retries on fclose/fflush after write errors

2012-03-13 Thread Rich Felker
On Tue, Mar 13, 2012 at 07:19:35PM +, u-uclibc-q...@aetey.se wrote:
  there's no correct/sane
  program that would be affected by this ABI change.
 
 Actually I suspect that stdio macros might use stuff (like __bufpos)
 which is located past the proposed new structure member, in which case
 existing binaries would become incompatible with a patched library:
 
   #endif /* __UCLIBC_HAS_WCHAR__ */
int __filedes;
  + int __errno_value;
   #ifdef __STDIO_BUFFERS
unsigned char *__bufstart;  /* pointer to buffer */
unsigned char *__bufend;/* pointer to 1 past end of buffer */
 -  unsigned char *__bufpos;

Indeed, I missed this. It should definitely not be added near the
beginning of the structure, only past elements that could be part of
the macro ABI.

Rich
___
uClibc mailing list
uClibc@uclibc.org
http://lists.busybox.net/mailman/listinfo/uclibc


Re: [PATCH] prevent retries on fclose/fflush after write errors

2012-03-13 Thread Mike Frysinger
On Tuesday 13 March 2012 01:58:49 Rich Felker wrote:
 On Tue, Mar 13, 2012 at 01:41:01AM -0400, Mike Frysinger wrote:
  On Sunday 11 March 2012 11:12:19 Denys Vlasenko wrote:
   --- a/libc/sysdeps/linux/common/bits/uClibc_stdio.h
   +++ b/libc/sysdeps/linux/common/bits/uClibc_stdio.h
   @@ -250,6 +250,7 @@ struct __STDIO_FILE_STRUCT {
 unsigned char __ungot[2];
#endif /* __UCLIBC_HAS_WCHAR__ */
 int __filedes;
   + int __errno_value;
#ifdef __STDIO_BUFFERS
 unsigned char *__bufstart;  /* pointer to buffer */
 unsigned char *__bufend;/* pointer to 1 past end of buffer */
  
  pretty sure this breaks ABI.  i know we aren't completely strict on this,
  but it's something we should avoid if possible.
 
 How so? Application code should not be touching the internals of
 FILE...

because the uClibc macros which implement the public API directly access the 
structure contents.  look at the getc macros and how it leverages the locking 
members.
-mike


signature.asc
Description: This is a digitally signed message part.
___
uClibc mailing list
uClibc@uclibc.org
http://lists.busybox.net/mailman/listinfo/uclibc

Re: [PATCH] prevent retries on fclose/fflush after write errors

2012-03-13 Thread Mike Frysinger
On Tuesday 13 March 2012 15:32:01 Rich Felker wrote:
 On Tue, Mar 13, 2012 at 07:19:35PM +, u-uclibc-q...@aetey.se wrote:
   there's no correct/sane
   program that would be affected by this ABI change.
  
  Actually I suspect that stdio macros might use stuff (like __bufpos)
  which is located past the proposed new structure member, in which case
  existing binaries would become incompatible with a patched library:
 
#endif /* __UCLIBC_HAS_WCHAR__ */
   int __filedes;
   +   int __errno_value;
#ifdef __STDIO_BUFFERS
   unsigned char *__bufstart;  /* pointer to buffer */
   unsigned char *__bufend;/* pointer to 1 past end of 
   buffer */
  
  -  unsigned char *__bufpos;
 
 Indeed, I missed this. It should definitely not be added near the
 beginning of the structure, only past elements that could be part of
 the macro ABI.

that would help only if the uClibc code itself had versioned functions which 
handled the growing struct.  if you're attempting to support code that 
allocated sizeof(FILE) memory (which is dumb), then location in the struct 
wouldn't matter.
-mike


signature.asc
Description: This is a digitally signed message part.
___
uClibc mailing list
uClibc@uclibc.org
http://lists.busybox.net/mailman/listinfo/uclibc

Re: [PATCH] prevent retries on fclose/fflush after write errors

2012-03-13 Thread u-uclibc-qs50
On Tue, Mar 13, 2012 at 04:24:33PM -0400, Mike Frysinger wrote:
  It should definitely not be added near the
  beginning of the structure, only past elements that could be part of
  the macro ABI.
 
 that would help only if the uClibc code itself had versioned functions which 
 handled the growing struct. 

Curious, why wouldn't this work without versioned functions?

FILE structures are expected to be allocated by the library and
used by 1. the library and 2. the macros. If we just add extra items
at the end, neither the new library code would be confused (it knows about
the new size and contents), nor the old application code would be confused
(the macros use[d] the offsets which did not change, the calls to
the functions pass pointers not structures).

Of course this generally only works if the macros are not being changed.

 if you're attempting to support code that 
 allocated sizeof(FILE) memory (which is dumb), then location in the struct 
 wouldn't matter.

I don't think keeping the size of FILE constant is practically important,
even though I mentioned this as an incompatibility.

Anyway, everyone now seems to agree that the proposed patch breaks the ABI :)

 -mike

Regards,
Rune

___
uClibc mailing list
uClibc@uclibc.org
http://lists.busybox.net/mailman/listinfo/uclibc


Re: [PATCH] prevent retries on fclose/fflush after write errors

2012-03-13 Thread Mike Frysinger
On Tuesday 13 March 2012 16:56:13 u-uclibc-q...@aetey.se wrote:
 On Tue, Mar 13, 2012 at 04:24:33PM -0400, Mike Frysinger wrote:
   It should definitely not be added near the
   beginning of the structure, only past elements that could be part of
   the macro ABI.
  
  that would help only if the uClibc code itself had versioned functions
  which handled the growing struct.
 
 Curious, why wouldn't this work without versioned functions?

if end user code encodes sizeof(FILE) anywhere, they're creating a memory 
region of a fixed number of bytes, so increasing the structure means that the 
app will give us a pointer to memory of X bytes, but the library requires it 
to be Y (where Y is greater than X) bytes, so the library will clobber memory 
the user did not intend.  declare char buf[sizeof(FILE)]; FILE *x = buf; on 
the stack and uClibc will overwrite random stuff on the stack.

 FILE structures are expected to be allocated by the library

your sub-thread here indicated that someone other than uClibc was allocating 
FILE structures (or i misread).  that cannot work w/out symbol versioning.

if uClibc is the only thing that allocates/uses these structures, then 
appending members should be fine.

 Of course this generally only works if the macros are not being changed.

correct, any existing members which are exposed via macros as part of the 
public API would have to remain in place.

  if you're attempting to support code that
  allocated sizeof(FILE) memory (which is dumb), then location in the
  struct wouldn't matter.
 
 I don't think keeping the size of FILE constant is practically important,
 even though I mentioned this as an incompatibility.

if by practically you mean we don't care about the end users who are relying 
on sizeof(FILE), then sure (i don't care about that use case).  i was just 
being pedantic in my reply.
-mike


signature.asc
Description: This is a digitally signed message part.
___
uClibc mailing list
uClibc@uclibc.org
http://lists.busybox.net/mailman/listinfo/uclibc

Re: [PATCH] prevent retries on fclose/fflush after write errors

2012-03-13 Thread Laurent Bercot
 alarm(1);
 fgets(buf, sizeof buf, f);
 
 I was assuming the old standard idiom of installing a do-nothing
 signal handler (without SA_RESTART) for SIGALRM so that fgets would
 return with an error and the program could proceed.

 Ugh. I get it. In this case, then, *of course* you want to get EINTR
reported to the user. And I already agreed that the libc should not
safe-wrap system calls, so yes, naturally fgets should be interrupted.

 But honestly, this seems to me like the lazy (in a bad sense) way to
write such a program; the right way would be to write a little
asynchronous select/poll loop with a timeout of 1 second and a reading
event on fd 0. The main reason why the latter paradigm isn't used as
much is that stdio doesn't handle partial reads and so is quite unusable
in asynchronous loops - in other words, stdio sucks.

 Whenever I need to listen to signals as events (or, in the case of
alarm(), as timeouts), I use a self-pipe and a select loop so I can
listen to any number of events at the same time. It's a bit harder to
program, but much more robust; the blocking system calls + EINTR
paradigm is ad-hoc and error-prone. It can break so easily, for instance
when your libc is misguided and safewraps around EINTR. ;)

-- 
 Laurent
___
uClibc mailing list
uClibc@uclibc.org
http://lists.busybox.net/mailman/listinfo/uclibc


Re: [PATCH] prevent retries on fclose/fflush after write errors

2012-03-13 Thread Rich Felker
On Tue, Mar 13, 2012 at 04:24:33PM -0400, Mike Frysinger wrote:
 #endif /* __UCLIBC_HAS_WCHAR__ */
  int __filedes;
+ int __errno_value;
 #ifdef __STDIO_BUFFERS
  unsigned char *__bufstart;  /* pointer to buffer */
  unsigned char *__bufend;/* pointer to 1 past end of 
buffer */
   
   -  unsigned char *__bufpos;
  
  Indeed, I missed this. It should definitely not be added near the
  beginning of the structure, only past elements that could be part of
  the macro ABI.
 
 that would help only if the uClibc code itself had versioned functions which 
 handled the growing struct.  if you're attempting to support code that 

No, there is no need for versioned functions. The uClibc code is in
uClibc and will always be using the version of FILE corresponding to
itself. Code in other libraries or applications only cares that FILE *
is a pointer (it might as well be void *) and about the offsets/types
of the buffer pointers (if getc/putc macros are enabled).

 allocated sizeof(FILE) memory (which is dumb), then location in the struct 
 wouldn't matter.

There's nothing useful/meaningful that such code could do.

Rich
___
uClibc mailing list
uClibc@uclibc.org
http://lists.busybox.net/mailman/listinfo/uclibc


Re: [PATCH] prevent retries on fclose/fflush after write errors

2012-03-13 Thread Rich Felker
On Tue, Mar 13, 2012 at 05:07:32PM -0400, Mike Frysinger wrote:
 On Tuesday 13 March 2012 16:56:13 u-uclibc-q...@aetey.se wrote:
  On Tue, Mar 13, 2012 at 04:24:33PM -0400, Mike Frysinger wrote:
It should definitely not be added near the
beginning of the structure, only past elements that could be part of
the macro ABI.
   
   that would help only if the uClibc code itself had versioned functions
   which handled the growing struct.
  
  Curious, why wouldn't this work without versioned functions?
 
 if end user code encodes sizeof(FILE) anywhere, they're creating a memory 
 region of a fixed number of bytes, so increasing the structure means that the 
 app will give us a pointer to memory of X bytes, but the library requires it 
 to be Y (where Y is greater than X) bytes, so the library will clobber memory 
 the user did not intend.  declare char buf[sizeof(FILE)]; FILE *x = buf; on 
 the stack and uClibc will overwrite random stuff on the stack.

Passing this FILE * to stdio functions invokes undefined behavior.
They all require a FILE * obtained from fopen/fdopen/popen/etc. or
from one of the standard stream pointers (stdin/stdout/stderr). The C
standard is very explicit that you are not allowed to use copies of
FILEs, and without copying an existing one, there's no way to
construct one that would be valid anyway.

  FILE structures are expected to be allocated by the library
 
 your sub-thread here indicated that someone other than uClibc was allocating 
 FILE structures (or i misread).  that cannot work w/out symbol versioning.
 
 if uClibc is the only thing that allocates/uses these structures, then 
 appending members should be fine.

No one but uClibc can allocate them.

Rich
___
uClibc mailing list
uClibc@uclibc.org
http://lists.busybox.net/mailman/listinfo/uclibc


Re: [PATCH] prevent retries on fclose/fflush after write errors

2012-03-13 Thread Rich Felker
On Tue, Mar 13, 2012 at 11:15:32PM +0100, Laurent Bercot wrote:
  alarm(1);
  fgets(buf, sizeof buf, f);
  
  I was assuming the old standard idiom of installing a do-nothing
  signal handler (without SA_RESTART) for SIGALRM so that fgets would
  return with an error and the program could proceed.
 
  Ugh. I get it. In this case, then, *of course* you want to get EINTR
 reported to the user. And I already agreed that the libc should not
 safe-wrap system calls, so yes, naturally fgets should be interrupted.

Yes, this is the sort of usage case I was talking about all along, and
as far as I can tell, really the only reason anybody would ever want
EINTR in the first place. Otherwise it's just a nuisance.

  But honestly, this seems to me like the lazy (in a bad sense) way to
 write such a program; the right way would be to write a little
 asynchronous select/poll loop with a timeout of 1 second and a reading
 event on fd 0. The main reason why the latter paradigm isn't used as
 much is that stdio doesn't handle partial reads and so is quite unusable
 in asynchronous loops - in other words, stdio sucks.

There are at least 3 ways to do it. You, and many people these days,
favor event-driven programming with select/poll/libevent/whatever.
This is certainly one reasonable design, but it tends to make things
that would otherwise be simple rather complicated, and precludes using
stdio. I wouldn't say this means stdio sucks; rather, it's just meant
for other types of programming.

The other 2 ways are the one I described (using EINTR) and threads
with thread cancellation as the method for getting out of blocked
situations. Both of these work quite well with stdio.

  Whenever I need to listen to signals as events (or, in the case of
 alarm(), as timeouts), I use a self-pipe and a select loop so I can
 listen to any number of events at the same time. It's a bit harder to
 program, but much more robust; the blocking system calls + EINTR
 paradigm is ad-hoc and error-prone. It can break so easily, for instance
 when your libc is misguided and safewraps around EINTR. ;)

Well I would call this not just misguided but wrong since POSIX
specifies that fgetc/fputc (and all other stdio functions defined in
terms of them) return failure with errno==EINTR for interrupting
signals...

Rich
___
uClibc mailing list
uClibc@uclibc.org
http://lists.busybox.net/mailman/listinfo/uclibc


Re: [PATCH] prevent retries on fclose/fflush after write errors

2012-03-11 Thread Denys Vlasenko
On Saturday 10 March 2012 23:55, Kevin Cernekee wrote:
 On Sat, Feb 12, 2011 at 6:31 PM, Denys Vlasenko
 vda.li...@googlemail.com wrote:
  Currently, uclibc retains buffered data on stdio write errors,
  and subsequent fclose and fflush will try to write it out again
  (in most cases, in vain).
 
 This seems to be causing some strange problems on bash as well.  Is
 there any interest in trying to mimic the glibc behavior?
 
 uClibc version is 0.9.32.1.
 
 
 bash problem:
 
 # bash --version
 GNU bash, version 3.2.0(1)-release (mipsel-unknown-linux-gnu)
 Copyright (C) 2005 Free Software Foundation, Inc.
 # echo none of the above  /sys/power/state
 sh: echo: write error: Invalid argument
 # a
 sh: a: command not found
 none of the abov# b
 sh: b: command not found
 none of the abov#
 # echo mem  /sys/power/state
 sh: echo: write error: Invalid argument
 # echo mem  /sys/power/state
 sh: echo: write error: Invalid argument
 # busybox echo mem  /sys/power/state
 PM: Syncing filesystems ... done.
 Freezing user space processes ... (elapsed 0.01 seconds) done.
 Freezing remaining freezable tasks ... (elapsed 0.01 seconds) done.
 Suspending console(s) (use no_console_suspend to debug)
 
 
 Simple test case to show that the buffered data persists (albeit in
 truncated form) even after calling fflush() and clearerr():
 
 -- 8 --
 
 #include stdio.h
 #include unistd.h
 #include fcntl.h
 
 int main(int argc, char **argv)
 {
   int tmpfd, fd;
 
   tmpfd = fcntl(fileno(stdout), F_DUPFD, 0);
   fd = open(/dev/null, O_RDONLY);
 
   dup2(fd, fileno(stdout));
 
   printf(hello world\n);
   fflush(stdout);
   if (ferror(stdout))
   clearerr(stdout);
 
   dup2(tmpfd, fileno(stdout));
 
   printf(goodbye world\n);
 
   return 0;
 }
 
 -- 8 --
 
 Output:
 
 # ./test
 hello worlgoodbye world


I propose the following patch.
Only compile tested by me, care to run-test?

-- 
vda


diff --git a/libc/stdio/_stdio.h b/libc/stdio/_stdio.h
index 2c0efc9..78069a5 100644
--- a/libc/stdio/_stdio.h
+++ b/libc/stdio/_stdio.h
@@ -212,7 +212,7 @@ extern int __stdio_seek(FILE *stream, register __offmax_t 
*pos, int whence) attr
 #define __STDIO_STREAM_SET_EOF(S) \
((void)((S)-__modeflags |= __FLAG_EOF))
 #define __STDIO_STREAM_SET_ERROR(S) \
-   ((void)((S)-__modeflags |= __FLAG_ERROR))
+   ((void)((S)-__errno_value = errno, (S)-__modeflags |= __FLAG_ERROR))
 
 #define __STDIO_STREAM_CLEAR_EOF(S) \
((void)((S)-__modeflags = ~__FLAG_EOF))
diff --git a/libc/stdio/clearerr.c b/libc/stdio/clearerr.c
index a96ecaa..af1d09f 100644
--- a/libc/stdio/clearerr.c
+++ b/libc/stdio/clearerr.c
@@ -7,6 +7,41 @@
 
 #include _stdio.h
 
+static inline void discard_buffered_data(FILE *stream)
+{
+#ifdef __STDIO_BUFFERS
+   /* Puty, but fpurge is rather non-portable,
+* thus many apps won't use it. Let them be able to clear
+* buffered data on write errors using clearerr().
+*/
+   if (__FERROR_UNLOCKED(stream)  /* was there indeed an error? */
+ __STDIO_STREAM_IS_WRITING(stream)
+ stream-__errno_value != 0
+ stream-__errno_value != EINTR
+ stream-__errno_value != EAGAIN
+/* add more non-fatal error codes here */
+   ) {
+   stream-__bufpos = stream-__bufstart;
+   /*
+* Prevent spurious buffer resets on superfluous clearerrs.
+* Example:
+*
+* close(fileno(stdout));
+* printf(Hi there!\n); // error happens here, data is 
buffered
+* dup2(good_fd, fileno(stdout));
+* clearerr(stdout);  // drops buffered data
+* printf(Hi there!);   // buffers new data
+* clearerr(stdout);  // must NOT drop newly buffered data
+*
+* We assure this by __FERROR_UNLOCKED check above,
+* and by clearing __errno_value below
+* (yes, I am a bit paranoid).
+*/
+   stream-__errno_value = 0;
+   }
+#endif
+}
+
 #undef clearerr
 #ifdef __DO_UNLOCKED
 
@@ -15,6 +50,8 @@ void clearerr_unlocked(register FILE *stream)
 {
__STDIO_STREAM_VALIDATE(stream);
 
+   discard_buffered_data(stream);
+
__CLEARERR_UNLOCKED(stream);
 }
 
@@ -32,6 +69,8 @@ void clearerr(register FILE *stream)
 
__STDIO_STREAM_VALIDATE(stream);
 
+   discard_buffered_data(stream);
+
__CLEARERR_UNLOCKED(stream);
 
__STDIO_AUTO_THREADUNLOCK(stream);
diff --git a/libc/stdio/fflush.c b/libc/stdio/fflush.c
index d9104a4..4599b58 100644
--- a/libc/stdio/fflush.c
+++ b/libc/stdio/fflush.c
@@ -134,8 +134,8 @@ int fflush_unlocked(register FILE *stream)
 * shouldn't flush a stream you were reading from.  As usual, 
glibc
 * caters to broken programs and simply ignores this. */
__UNDEFINED_OR_NONPORTABLE;
-   

Re: [PATCH] prevent retries on fclose/fflush after write errors

2012-03-11 Thread Denys Vlasenko
On Sunday 11 March 2012 18:10, Rich Felker wrote:
 On Sun, Mar 11, 2012 at 04:12:19PM +0100, Denys Vlasenko wrote:
  On Sunday 11 March 2012 14:46, Denys Vlasenko wrote:
   I propose the following patch.
   Only compile tested by me, care to run-test?
  
  A more correct (I hope) version:
 
 I'm curious why this is such a big patch introducing new functions and
 struct members. Couldn't it be just a one-line change in the function
 that writes out the buffers (i.e. do the buffer-voiding as soon as the
 error is hit rather than testing for it later)?

EINTR and EAGAIN should not result in output buffers being dropped.
You need to remember the error code for this.

 Perhaps I'm missing 
 something about uclibc's design that makes this not work well, but
 it's how my implementation in musl has always done it and I could
 switch to the bad glibc behavior just by changing one line...

How about this simpler one?


--- a/libc/stdio/_WRITE.c
+++ b/libc/stdio/_WRITE.c
@@ -58,13 +58,29 @@ size_t attribute_hidden __stdio_WRITE(register FILE *stream,
todo -= rv;
buf += rv;
} else
-#ifdef __UCLIBC_MJN3_ONLY__
-#warning EINTR?
-#endif
-/* if (errno != EINTR) */
-   {
-   __STDIO_STREAM_SET_ERROR(stream);
 
+   __STDIO_STREAM_SET_ERROR(stream);
+
+   /* We buffer data on transient errors, but discard it
+* on hard ones. Example of a hard error:
+*
+* close(fileno(stdout));
+* printf(Hi there 1\n); // EBADF
+* dup2(good_fd, fileno(stdout));
+* printf(Hi there 2\n); // buffers new data
+*
+* This program should not print Hi there 1 to good_fd.
+* The rationale is that the caller of writing operation
+* should check for error and act on it.
+* If he didn't, then future users of the stream
+* have no idea what to do.
+* It's least confusing to at least not burden them with
+* some hidden buffered crap in the buffer.
+*/
+   if (errno == EINTR
+|| errno == EAGAIN
+/* do we have other soft errors? */
+   ) {
 #ifdef __STDIO_BUFFERS
stodo = __STDIO_STREAM_BUFFER_SIZE(stream);
if (stodo != 0) {
___
uClibc mailing list
uClibc@uclibc.org
http://lists.busybox.net/mailman/listinfo/uclibc


Re: [PATCH] prevent retries on fclose/fflush after write errors

2012-03-10 Thread Kevin Cernekee
On Sat, Feb 12, 2011 at 6:31 PM, Denys Vlasenko
vda.li...@googlemail.com wrote:
 Currently, uclibc retains buffered data on stdio write errors,
 and subsequent fclose and fflush will try to write it out again
 (in most cases, in vain).

This seems to be causing some strange problems on bash as well.  Is
there any interest in trying to mimic the glibc behavior?

uClibc version is 0.9.32.1.


bash problem:

# bash --version
GNU bash, version 3.2.0(1)-release (mipsel-unknown-linux-gnu)
Copyright (C) 2005 Free Software Foundation, Inc.
# echo none of the above  /sys/power/state
sh: echo: write error: Invalid argument
# a
sh: a: command not found
none of the abov# b
sh: b: command not found
none of the abov#
# echo mem  /sys/power/state
sh: echo: write error: Invalid argument
# echo mem  /sys/power/state
sh: echo: write error: Invalid argument
# busybox echo mem  /sys/power/state
PM: Syncing filesystems ... done.
Freezing user space processes ... (elapsed 0.01 seconds) done.
Freezing remaining freezable tasks ... (elapsed 0.01 seconds) done.
Suspending console(s) (use no_console_suspend to debug)


Simple test case to show that the buffered data persists (albeit in
truncated form) even after calling fflush() and clearerr():

-- 8 --

#include stdio.h
#include unistd.h
#include fcntl.h

int main(int argc, char **argv)
{
int tmpfd, fd;

tmpfd = fcntl(fileno(stdout), F_DUPFD, 0);
fd = open(/dev/null, O_RDONLY);

dup2(fd, fileno(stdout));

printf(hello world\n);
fflush(stdout);
if (ferror(stdout))
clearerr(stdout);

dup2(tmpfd, fileno(stdout));

printf(goodbye world\n);

return 0;
}

-- 8 --

Output:

# ./test
hello worlgoodbye world
#
___
uClibc mailing list
uClibc@uclibc.org
http://lists.busybox.net/mailman/listinfo/uclibc


Re: [PATCH] prevent retries on fclose/fflush after write errors

2011-02-11 Thread Bernhard Reutner-Fischer
Denys Vlasenko vda.li...@googlemail.com wrote:

Currently, uclibc retains buffered data on stdio write errors,
and subsequent fclose and fflush will try to write it out again
(in most cases, in vain).

Which results in something like this:

On Wednesday 26 January 2011 13:21, Baruch Siach wrote:
 Hi busybox list,
 
 I'm running the following command under strace (thanks Rob):
 
 echo 56  /sys/class/gpio/export
 
 and I see the following output:
 
 write(1, 56\n, 3) = -1 EBUSY (Device or
resource busy)
 write(1, 5, 1)= 1
 
 The first EBUSY is OK, since GPIO 56 is already requested. But the
second 
 write() attempt seems strange, and leads to an unwanted outcome. GPIO
5 gets 
 exported.


This patch prevents that.

-- 
vda

diff -d -urpN uClibc.0/libc/stdio/_wcommit.c
uClibc.1/libc/stdio/_wcommit.c
--- uClibc.0/libc/stdio/_wcommit.c 2011-02-07 00:04:34.0 +0100
+++ uClibc.1/libc/stdio/_wcommit.c 2011-02-07 00:55:24.0 +0100
@@ -20,7 +20,18 @@ size_t attribute_hidden __stdio_wcommit(
 
   __STDIO_STREAM_VALIDATE(stream);
 
-  if ((bufsize = __STDIO_STREAM_BUFFER_WUSED(stream)) != 0) {
+  /* Note: we do not write anything if write error has been detected.
+   * Otherwise, stdio user has no way to prevent retries after
+   * failed write - and some users do want to not have any retries!
+   * IOW: if write errored out, neither fflush nor fclose should
+   * try to write buffered data.
+   * clearerr may be used to enable retry if needed.
+   */
+
+  bufsize = __STDIO_STREAM_BUFFER_WUSED(stream);
+  if (bufsize != 0
+!(stream-__modeflags  __FLAG_ERROR)
+  ) {
   stream-__bufpos = stream-__bufstart;
   __stdio_WRITE(stream, stream-__bufstart, bufsize);
   }

Hi,

Sounds plausible (but I did not check the standard), please install.
___
uClibc mailing list
uClibc@uclibc.org
http://lists.busybox.net/mailman/listinfo/uclibc