[Toybox] [PATCH] grep: add --line-buffered and fix regular buffering.
Rob Landley
rob at landley.net
Sun Feb 24 15:32:02 PST 2019
On 2/24/19 4:27 PM, enh via Toybox wrote:
> This is slightly more involved than just calling setlinebuf(3) because
> the code was already implicitly flushing more than once per line thanks
> to all the calls to the 'x' wrappers around stdio.
Most of them can go, I tend to err on the side of error checking (which requires
a flush to see if it worked) and then pull back later. (The xexit() code checks
at the end, but you want to catch things like "disk full" or a broken pipe
earlier rather than sitting there spinning...)
> I've un-'x'ed putsl and putsn, given that the only caller doesn't want
> to flush that often, but I left them in lib/ for now.
>
> As usual I haven't added a bogus short option to correspond to
> --line-buffered because I fear that one day (when it's many years
> of existing practice too late to fix either side) we'll end up with
> a collision.
Many moons ago I taught busybox mount to autodetect when it needed to do
loopback mounts so you didn't need to say -o loop, and util-linux eventually
caught up and did that too. They do sometimes accept sufficiently widespread
external practice. :)
But yeah, syntax for --longopt without short opt exists for a reason...
> Tested by looking at `strace -e write` output when running
> `grep fpu_ /proc/cpuinfo > /dev/null` with and without --line-buffered
> (the redirection is necessary because stdout is line buffered by default
> if it's a terminal).
> ---
> lib/lib.c | 17 +++++++++++++++++
> lib/lib.h | 4 ++--
> lib/xwrap.c | 19 -------------------
> toys/posix/grep.c | 31 ++++++++++++++++---------------
> 4 files changed, 35 insertions(+), 36 deletions(-)
The "x" prefix means "can error_exit()" (patient zero of which was xmalloc()),
the flush was just necessary to do said checking reliably. Your new ones can
still error_exit(), so technically they'd still be x without the flush.
Of course this raises the "some flush and some don't spectre..." Hmmm. How about:
diff --git a/lib/xwrap.c b/lib/xwrap.c
index 12016a2..ea3e9f1 100644
--- a/lib/xwrap.c
+++ b/lib/xwrap.c
@@ -143,7 +143,7 @@ char *xmprintf(char *format, ...)
void xflush(void)
{
- if (fflush(0) || ferror(stdout)) perror_exit("write");
+ if ((!toys.noflush && fflush(0)) || ferror(stdout)) perror_exit("write");
}
void xprintf(char *format, ...)
diff --git a/toys.h b/toys.h
index 9e49900..40eca86 100644
--- a/toys.h
+++ b/toys.h
@@ -106,6 +106,7 @@ extern struct toy_context {
int signalfd; // and writes signal to this fd, if set
char exitval; // Value error_exit feeds to exit()
char wasroot; // dropped setuid
+ char noflush; // tell xflush() not to (for performance).
// This is at the end so toy_init() doesn't zero it.
sigjmp_buf *rebound; // siglongjmp here instead of exit when do_rebound
If that looks like a reasonable approach, I can try to chop this patch down to
what it actually does if you don't want to resubmit. (Note: xexit() already does
the flush itself because error_msg() not error_exit()...)
Rob
More information about the Toybox
mailing list