From 20ec15d66a1ba0c1089f145a482b326eca3aef5f Mon Sep 17 00:00:00 2001 From: cheloha Date: Wed, 28 Dec 2022 20:56:37 +0000 Subject: [PATCH] iostat(8): implement periodic display with setitimer(2) Prefer setitimer(2)+sigsuspend(2) to nanosleep(2) when performing periodic work. The latter drifts. Link: https://marc.info/?l=openbsd-tech&m=167068674625838&w=2 ok millert@ --- usr.sbin/iostat/iostat.c | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/usr.sbin/iostat/iostat.c b/usr.sbin/iostat/iostat.c index e8c1b96ac8e..0afbe0b6e76 100644 --- a/usr.sbin/iostat/iostat.c +++ b/usr.sbin/iostat/iostat.c @@ -1,4 +1,4 @@ -/* $OpenBSD: iostat.c,v 1.45 2022/12/04 23:50:51 cheloha Exp $ */ +/* $OpenBSD: iostat.c,v 1.46 2022/12/28 20:56:37 cheloha Exp $ */ /* $NetBSD: iostat.c,v 1.10 1996/10/25 18:21:58 scottr Exp $ */ /* @@ -68,10 +68,12 @@ #include #include +#include #include #include #include #include +#include #include #include @@ -85,7 +87,8 @@ extern int dk_ndrive; kvm_t *kd; char *nlistf, *memf; -int hz, reps, interval; +int hz, reps; +time_t interval; static int todo = 0; volatile sig_atomic_t wantheader; @@ -100,6 +103,7 @@ volatile sig_atomic_t wantheader; static void cpustats(void); static void disk_stats(double); static void disk_stats2(double); +static void sigalarm(int); static void sigheader(int); static void header(void); static void usage(void); @@ -113,9 +117,10 @@ int dkinit(int); int main(int argc, char *argv[]) { + struct itimerval itv; const char *errstr; + sigset_t empty; int ch, hdrcnt; - struct timespec ts; while ((ch = getopt(argc, argv, "Cc:dDIM:N:Tw:")) != -1) switch(ch) { @@ -146,7 +151,7 @@ main(int argc, char *argv[]) todo |= SHOW_TTY; break; case 'w': - interval = strtonum(optarg, 1, 100000000, &errstr); + interval = strtonum(optarg, 1, UINT_MAX, &errstr); if (errstr) errx(1, "wait is %s", errstr); break; @@ -169,12 +174,20 @@ main(int argc, char *argv[]) dkreadstats(); selectdrives(argv); - ts.tv_sec = interval; - ts.tv_nsec = 0; - /* print a new header on sigcont */ signal(SIGCONT, sigheader); + if (interval != 0) { + if (signal(SIGALRM, sigalarm) == SIG_ERR) + err(1, "signal"); + sigemptyset(&empty); + itv.it_value.tv_sec = interval; + itv.it_value.tv_usec = 0; + itv.it_interval = itv.it_value; + if (setitimer(ITIMER_REAL, &itv, NULL) == -1) + err(1, "setitimer"); + } + for (hdrcnt = 1;;) { if (!--hdrcnt || wantheader) { header(); @@ -188,7 +201,7 @@ main(int argc, char *argv[]) if (reps >= 0 && --reps <= 0) break; - nanosleep(&ts, NULL); + sigsuspend(&empty); dkreadstats(); if (last.dk_ndrive != cur.dk_ndrive) wantheader = 1; @@ -196,6 +209,11 @@ main(int argc, char *argv[]) exit(0); } +static void +sigalarm(int signo) +{ +} + /*ARGSUSED*/ static void sigheader(int signo) @@ -421,7 +439,7 @@ selectdrives(char *argv[]) errx(1, "invalid interval or drive name: %s", *argv); } if (*argv) { - interval = strtonum(*argv, 1, 100000000, &errstr); + interval = strtonum(*argv, 1, UINT_MAX, &errstr); if (errstr) errx(1, "interval is %s", errstr); if (*++argv) { -- 2.20.1