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