From 6f9574e0c8dab84ccdef89d380950c7af2911963 Mon Sep 17 00:00:00 2001 From: cheloha Date: Thu, 5 May 2022 22:36:36 +0000 Subject: [PATCH] kstat(1): implement wait with setitimer(2) instead of nanosleep(2) kstat(1)'s wait period drifts because nanosleep(2) uses a relative timeout. If we use setitimer(2)/sigsuspend(2) the period does not drift. While here, bump the upper bound for wait up to UINT_MAX and switch to the normal strtonum(3) error message format. With input from kn@. Tweaked by bluhm@ to block SIGALRM with sigprocmask(2) while we're outside of sigsuspend(2). Thread: https://marc.info/?l=openbsd-tech&m=160038548111187&w=2 Earlier version ok millert@. ok bluhm@ --- usr.bin/kstat/kstat.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/usr.bin/kstat/kstat.c b/usr.bin/kstat/kstat.c index 166d55e3074..2ce845bfa6f 100644 --- a/usr.bin/kstat/kstat.c +++ b/usr.bin/kstat/kstat.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kstat.c,v 1.9 2022/04/22 00:29:20 dlg Exp $ */ +/* $OpenBSD: kstat.c,v 1.10 2022/05/05 22:36:36 cheloha Exp $ */ /* * Copyright (c) 2020 David Gwynne @@ -15,6 +15,8 @@ */ #include +#include +#include #include #include #include @@ -104,6 +106,7 @@ kstat_cmp(const struct kstat_entry *ea, const struct kstat_entry *eb) RBT_PROTOTYPE(kstat_tree, kstat_entry, entry, kstat_cmp); RBT_GENERATE(kstat_tree, kstat_entry, entry, kstat_cmp); +static void handle_alrm(int); static struct kstat_filter * kstat_filter_parse(char *); static int kstat_filter_entry(struct kstat_filters *, @@ -134,16 +137,17 @@ main(int argc, char *argv[]) int fd; const char *errstr; int ch; - struct timespec interval = { 0, 0 }; + struct itimerval itv; + sigset_t empty, mask; int i; + unsigned int wait = 0; while ((ch = getopt(argc, argv, "w:")) != -1) { switch (ch) { case 'w': - interval.tv_sec = strtonum(optarg, 1, 100000000, - &errstr); + wait = strtonum(optarg, 1, UINT_MAX, &errstr); if (errstr != NULL) - errx(1, "wait %s: %s", optarg, errstr); + errx(1, "wait is %s: %s", errstr, optarg); break; default: usage(); @@ -168,12 +172,25 @@ main(int argc, char *argv[]) kstat_list(&kt, fd, version, &kfs); kstat_print(&kt); - if (interval.tv_sec == 0) + if (wait == 0) return (0); - for (;;) { - nanosleep(&interval, NULL); + if (signal(SIGALRM, handle_alrm) == SIG_ERR) + err(1, "signal"); + sigemptyset(&empty); + sigemptyset(&mask); + sigaddset(&mask, SIGALRM); + if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) + err(1, "sigprocmask"); + + itv.it_value.tv_sec = wait; + itv.it_value.tv_usec = 0; + itv.it_interval = itv.it_value; + if (setitimer(ITIMER_REAL, &itv, NULL) == -1) + err(1, "setitimer"); + for (;;) { + sigsuspend(&empty); kstat_read(&kt, fd); kstat_print(&kt); } @@ -548,3 +565,8 @@ kstat_read(struct kstat_tree *kt, int fd) err(1, "update id %llu", ksreq->ks_id); } } + +static void +handle_alrm(int signo) +{ +} -- 2.20.1