From cbf5708f4336b824b85366d55d42235852183b83 Mon Sep 17 00:00:00 2001 From: dds Date: Sat, 11 Oct 2003 20:34:43 +0000 Subject: - Check and report write(2) errors. - Issue a single writev(2) call instead of multiple write(2)s. This change improves the inefficiencies introduced when echo went on an stdio diet. The following figures are for echoing 1000 arguments. original stdio-based echo: 0.01 real 0.01 user 0.00 sys before: 0.05 real 0.00 user 0.04 sys after: 0.01 real 0.00 user 0.00 sys --- bin/echo/echo.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 59 insertions(+), 10 deletions(-) (limited to 'bin/echo') diff --git a/bin/echo/echo.c b/bin/echo/echo.c index 85a9efa..cb0c789 100644 --- a/bin/echo/echo.c +++ b/bin/echo/echo.c @@ -45,23 +45,56 @@ static char sccsid[] = "@(#)echo.c 8.1 (Berkeley) 5/31/93"; #include __FBSDID("$FreeBSD$"); -#include +#include +#include + +#include +#include +#include +#include #include +#include -/* ARGSUSED */ +/* + * Report an error and exit. + * Use it instead of err(3) to avoid linking-in stdio. + */ +static void +errexit(const char *prog, const char *reason) +{ + char *errstr = strerror(errno); + write(STDERR_FILENO, prog, strlen(prog)); + write(STDERR_FILENO, ": ", 2); + write(STDERR_FILENO, reason, strlen(reason)); + write(STDERR_FILENO, ": ", 2); + write(STDERR_FILENO, errstr, strlen(errstr)); + write(STDERR_FILENO, "\n", 1); + exit(1); +} + int -main(int argc __unused, char *argv[]) +main(int argc, char *argv[]) { int nflag; /* if not set, output a trailing newline. */ + int veclen; /* number of writev arguments. */ + struct iovec *iov, *vp; /* Elements to write, current element. */ + char space[] = " "; + char newline[] = "\n"; + char *progname = argv[0]; /* This utility may NOT do getopt(3) option parsing. */ if (*++argv && !strcmp(*argv, "-n")) { ++argv; + --argc; nflag = 1; - } - else + } else nflag = 0; + veclen = (argc >= 2) ? (argc - 2) * 2 + 1 : 0; + + if ((vp = iov = malloc((veclen + 1) * sizeof(struct iovec))) == NULL) + errexit(progname, "malloc"); + while (argv[0] != NULL) { size_t len; @@ -82,11 +115,27 @@ main(int argc __unused, char *argv[]) nflag = 1; } } - write(STDOUT_FILENO, argv[0], len); - if (*++argv) - write(STDOUT_FILENO, " ", 1); + vp->iov_base = *argv; + vp++->iov_len = len; + if (*++argv) { + vp->iov_base = space; + vp++->iov_len = 1; + } + } + if (!nflag) { + veclen++; + vp->iov_base = newline; + vp++->iov_len = 1; + } + /* assert(veclen == (vp - iov)); */ + while (veclen) { + int nwrite; + + nwrite = (veclen > IOV_MAX) ? IOV_MAX : veclen; + if (writev(STDOUT_FILENO, iov, nwrite) == -1) + errexit(progname, "write"); + iov += nwrite; + veclen -= nwrite; } - if (!nflag) - write(STDOUT_FILENO, "\n", 1); return 0; } -- cgit v1.1