Source-Changes-HG archive

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

[src/trunk]: src/tests/lib/libc/stdio fixes from RVP



details:   https://anonhg.NetBSD.org/src/rev/720faa627709
branches:  trunk
changeset: 984466:720faa627709
user:      christos <christos%NetBSD.org@localhost>
date:      Fri Jul 09 15:26:59 2021 +0000

description:
fixes from RVP

diffstat:

 tests/lib/libc/stdio/h_intr.c  |  277 +++++++++++++++++++++++++++++-----------
 tests/lib/libc/stdio/t_intr.sh |    4 +-
 2 files changed, 204 insertions(+), 77 deletions(-)

diffs (truncated from 479 to 300 lines):

diff -r cb868fe6389c -r 720faa627709 tests/lib/libc/stdio/h_intr.c
--- a/tests/lib/libc/stdio/h_intr.c     Fri Jul 09 09:24:16 2021 +0000
+++ b/tests/lib/libc/stdio/h_intr.c     Fri Jul 09 15:26:59 2021 +0000
@@ -1,20 +1,20 @@
-/*     $NetBSD: h_intr.c,v 1.2 2021/07/08 15:21:40 christos Exp $      */
+/*     $NetBSD: h_intr.c,v 1.3 2021/07/09 15:26:59 christos Exp $      */
 
 /**
- * Test of interrupted writes to popen()'ed commands.
+ * Test of interrupted I/O to popen()ed commands.
  *
  * Example 1:
- * ./h_fwrite -c "gzip -t" *.gz
+ * ./h_intr -c "gzip -t" *.gz
  *
  * Example 2:
- * while :; do ./h_fwrite -b $((12*1024)) -t 10 -c "bzip2 -t" *.bz2; sleep 2; done
+ * while :; do ./h_intr -b $((12*1024)) -t 10 -c "bzip2 -t" *.bz2; sleep 2; done
  *
  * Example 3:
  * Create checksum file:
  * find /mnt -type f -exec sha512 -n {} + >SHA512
  *
  * Check program:
- * find /mnt -type f -exec ./h_fwrite -b 512 -c run.sh {} +
+ * find /mnt -type f -exec ./h_intr -b 512 -c run.sh {} +
  * 
  * ./run.sh:
        #!/bin/sh
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: h_intr.c,v 1.2 2021/07/08 15:21:40 christos Exp $");
+__RCSID("$NetBSD: h_intr.c,v 1.3 2021/07/09 15:26:59 christos Exp $");
 
 #include <time.h>
 #include <err.h>
@@ -38,25 +38,29 @@
 #include <string.h>
 #include <unistd.h>
 
-static int process(const char *fn);
+static bool process(const char *fn);
 ssize_t maxread(FILE *fp, void *buf, size_t size);
 ssize_t smaxread(FILE *fp, void *buf, size_t size);
 ssize_t maxwrite(FILE *fp, const void *buf, size_t size);
 ssize_t smaxwrite(FILE *fp, const void *buf, size_t size);
+static int rndbuf(void);
+static int rndmode(void);
 static sig_t xsignal(int signo, sig_t handler);
 static void alarmtimer(int wait);
 static void pr_star(int signo);
-static bool isvalid(const char *s);
 static int do_opts(int argc, char* argv[]);
-static void usage(FILE* fp);
+static void usage(FILE *fp);
 
 /* Globals */
 static struct options {
-       size_t bsize;
-       size_t ssize;
-       int btype;
-       int tmout;
-       const char *cmd;
+       char* cmd;              /* cmd to run (which must read from stdin) */
+       size_t bsize;           /* block size to use */
+       size_t asize;           /* alt. stdio buffer size */
+       int btype;              /* buffering type: _IONBF, ... */
+       int tmout;              /* alarm timeout */
+       int flush;              /* call fflush() after write if 1 */
+       int rndbuf;             /* switch buffer randomly if 1 */
+       int rndmod;             /* switch buffering modes randomly if 1 */
 } opts;
 
 static const struct {
@@ -68,15 +72,24 @@
        { "IOFBF", _IOFBF },
 };
 
+static void (*alarm_fn)(int);                          /* real/dummy alarm fn. */
+static int (*sintr_fn)(int, int);                      /*  " siginterrupt fn. */
+static ssize_t (*rd_fn)(FILE*, void*, size_t);         /* read fn. */
+static ssize_t (*wr_fn)(FILE*, const void*, size_t);   /* write fn. */
+
 enum {
-       MB = 1024 * 1024,
-       BSIZE = 16 * 1024,
-       DEF_MS = 100,
-       MS = 1000,
+       MB = 1024 * 1024,       /* a megabyte */
+       BSIZE = 16 * 1024,      /* default RW buffer size */
+       DEF_MS = 100,           /* interrupt 10x a second */
+       MS = 1000,              /* msecs. in a second */
 };
 
 
 
+
+/**
+ * M A I N
+ */
 int
 main(int argc, char* argv[])
 {
@@ -100,8 +113,8 @@
 
                sig_t osig = xsignal(SIGALRM, pr_star);
 
-               if (process(argv[i]) == 0)
-                       printf("ok\n");
+               if (process(argv[i]) == true)
+                       printf(" OK\n");
                else
                        rc = EXIT_FAILURE;
 
@@ -111,46 +124,79 @@
        return rc;
 }
 
-static int
+static bool
 process(const char *fn)
 {
        FILE *ifp, *ofp;
-       char *buf;
+       char *buf, *abuf;
+       int rc = false;
        size_t nw = 0;
-       int rc = EXIT_FAILURE;
        ssize_t n;
 
-       if ((buf = malloc(opts.bsize)) == NULL)
-               err(rc, "buffer alloc failed");
+       abuf = NULL;
 
-       if ((ifp = fopen(fn, "r")) == NULL) {
-               warn("fopen failed: %s", fn);
+       if ((buf = malloc(opts.bsize)) == NULL) {
+               warn("buffer alloc failed");
                return rc;
        }
 
-       if ((ofp = popen(opts.cmd, "w")) == NULL)
-               err(rc, "popen failed `%s'", opts.cmd);
+       if ((abuf = malloc(opts.asize)) == NULL) {
+               warn("alt. buffer alloc failed");
+               goto fail;
+       }
+
+       if ((ifp = fopen(fn, "r")) == NULL) {
+               warn("fopen failed: %s", fn);
+               goto fail;
+       }
+
+       if ((ofp = popen(opts.cmd, "w")) == NULL) {
+               warn("popen failed `%s'", opts.cmd);
+               goto fail;
+       }
 
-       setvbuf(ofp, NULL, opts.btype, opts.ssize);
-       setvbuf(ifp, NULL, opts.btype, opts.ssize);
+       setvbuf(ofp, NULL, opts.btype, opts.asize);
+       setvbuf(ifp, NULL, opts.btype, opts.asize);
+
+       alarm_fn(opts.tmout);
+
+       while ((n = rd_fn(ifp, buf, opts.bsize)) > 0) {
+               ssize_t i;
 
-       alarmtimer(opts.tmout);
-       while ((n = maxread(ifp, buf, opts.bsize)) > 0) {
-               ssize_t i;
-               if ((i = maxwrite(ofp, buf, n)) == -1) {
+               if (opts.rndbuf || opts.rndmod) {
+                       int r = rndbuf();
+                       setvbuf(ofp, r ? abuf : NULL,
+                               rndmode(), r ? opts.asize : 0);
+               }
+
+               sintr_fn(SIGALRM, 0);
+
+               if ((i = wr_fn(ofp, buf, n)) == -1) {
+                       sintr_fn(SIGALRM, 1);
                        warn("write failed");
                        break;
                }
+
+               if (opts.flush)
+                       if (fflush(ofp))
+                               warn("fflush failed");
+
+               sintr_fn(SIGALRM, 1);
                nw += i;
        }
-       alarmtimer(0);
+
+       alarm_fn(0);
        // printf("%zu\n", nw);
 
        fclose(ifp);
        if (pclose(ofp) != 0)
                warn("command failed `%s'", opts.cmd);
        else
-               rc = EXIT_SUCCESS;
+               rc = true;
+
+fail:
+       free(abuf);
+       free(buf);
 
        return rc;
 }
@@ -238,7 +284,7 @@
 }
 
 /**
- * maxwrite - stdio version (substrate is buggy)
+ * maxwrite - stdio version (warning: substrate may be buggy)
  */
 ssize_t
 maxwrite(FILE* fp, const void* buf, size_t size)
@@ -268,6 +314,28 @@
        return nwr;
 }
 
+static int
+rndbuf(void)
+{
+       if (opts.rndbuf == 0)
+               return 0;
+       return arc4random_uniform(2);
+}
+
+static int
+rndmode(void)
+{
+       if (opts.rndmod == 0)
+               return opts.btype;
+
+       switch (arc4random_uniform(3)) {
+       case 0: return _IONBF;
+       case 1: return _IOLBF;
+       case 2: return _IOFBF;
+       default: errx(EXIT_FAILURE, "programmer error!");
+       }
+}
+
 /**
  * wrapper around sigaction() because we want POSIX semantics:
  * no auto-restarting of interrupted slow syscalls.
@@ -296,6 +364,20 @@
        setitimer(ITIMER_REAL, &itv, NULL); 
 }
 
+static void
+dummytimer(int dummy)
+{
+       (void)dummy;
+}
+
+static int
+dummysintr(int dum1, int dum2)
+{
+       (void)dum1;
+       (void)dum2;
+       return 0;       /* OK */
+}
+
 /**
  * Print a `*' each time an alarm signal occurs.
  */
@@ -312,42 +394,60 @@
 }
 
 /**
- * return true if not empty or blank; FAIL otherwise.
+ * return true if not empty or blank; false otherwise.
  */
 static bool
 isvalid(const char *s)
 {
-       if (*s == '\0')
-               return false;
        return strspn(s, " \t") != strlen(s);
 }
 
 static const char *
-getbtype(int val) {
+btype2str(int val)
+{
        for (size_t i = 0; i < __arraycount(btypes); i++)
                if (btypes[i].value == val)
                        return btypes[i].name;
        return "*invalid*";
 }
 
+static int
+str2btype(const char* s)
+{



Home | Main Index | Thread Index | Old Index