diff options
author | Aaron Campbell <aaron@cvs.openbsd.org> | 2004-06-28 01:34:47 +0000 |
---|---|---|
committer | Aaron Campbell <aaron@cvs.openbsd.org> | 2004-06-28 01:34:47 +0000 |
commit | fb8afb0fc41ef3fe4cd5cc7bdb475fd4156c546f (patch) | |
tree | f74d6135fb63cd5fe8ab0273bc96c8d8e61ce444 | |
parent | 41dde1384131189f656d524751329b4be86e4de1 (diff) |
Add new, generic ``evcount'' event counter API to the kernel. From art@,
with modifications from me. Includes code for generic interrupt counter
fetching via sysctl. deraadt@ tholo@ drahn@ millert@ ok
-rw-r--r-- | sys/conf/files | 3 | ||||
-rw-r--r-- | sys/kern/kern_sysctl.c | 17 | ||||
-rw-r--r-- | sys/kern/subr_evcount.c | 188 | ||||
-rw-r--r-- | sys/sys/evcount.h | 59 | ||||
-rw-r--r-- | sys/sys/sysctl.h | 11 |
5 files changed, 272 insertions, 6 deletions
diff --git a/sys/conf/files b/sys/conf/files index 9b47c4b7f66..bf78fe03ff1 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,4 +1,4 @@ -# $OpenBSD: files,v 1.307 2004/06/22 23:55:23 millert Exp $ +# $OpenBSD: files,v 1.308 2004/06/28 01:34:46 aaron Exp $ # $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $ # @(#)files.newconf 7.5 (Berkeley) 5/10/93 @@ -578,6 +578,7 @@ file kern/kern_xxx.c file kern/kgdb_stub.c kgdb file kern/subr_autoconf.c file kern/subr_disk.c +file kern/subr_evcount.c file kern/subr_extent.c file kern/subr_log.c file kern/subr_pool.c diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c index 0a4235942a7..4b83109ba96 100644 --- a/sys/kern/kern_sysctl.c +++ b/sys/kern/kern_sysctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_sysctl.c,v 1.116 2004/06/25 08:41:19 art Exp $ */ +/* $OpenBSD: kern_sysctl.c,v 1.117 2004/06/28 01:34:46 aaron Exp $ */ /* $NetBSD: kern_sysctl.c,v 1.17 1996/05/20 17:49:05 mrg Exp $ */ /*- @@ -62,6 +62,9 @@ #include <sys/exec.h> #include <sys/mbuf.h> #include <sys/sensors.h> +#ifdef __HAVE_EVCOUNT +#include <sys/evcount.h> +#endif #include <sys/mount.h> #include <sys/syscallargs.h> @@ -279,6 +282,9 @@ kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) case KERN_INTRCNT: case KERN_WATCHDOG: case KERN_EMUL: +#ifdef __HAVE_EVCOUNT + case KERN_EVCOUNT: +#endif break; default: return (ENOTDIR); /* overloaded */ @@ -517,6 +523,11 @@ kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) if (!error) nmbclust_update(); return (error); +#ifdef __HAVE_EVCOUNT + case KERN_EVCOUNT: + return (evcount_sysctl(name + 1, namelen - 1, oldp, oldlenp, + newp, newlen)); +#endif default: return (EOPNOTSUPP); } @@ -1762,6 +1773,9 @@ sysctl_sysvipc(name, namelen, where, sizep) int sysctl_intrcnt(int *name, u_int namelen, void *oldp, size_t *oldlenp) { +#ifdef __HAVE_EVCOUNT + return (evcount_sysctl(name, namelen, oldp, oldlenp, NULL, 0)); +#else extern int intrcnt[], eintrcnt[]; extern char intrnames[], eintrnames[]; char *intrname; @@ -1795,6 +1809,7 @@ sysctl_intrcnt(int *name, u_int namelen, void *oldp, size_t *oldlenp) default: return (EOPNOTSUPP); } +#endif } int nsensors = 0; diff --git a/sys/kern/subr_evcount.c b/sys/kern/subr_evcount.c new file mode 100644 index 00000000000..4cccf3239d8 --- /dev/null +++ b/sys/kern/subr_evcount.c @@ -0,0 +1,188 @@ +/* $OpenBSD: subr_evcount.c,v 1.1 2004/06/28 01:34:46 aaron Exp $ */ +/* + * Copyright (c) 2004 Artur Grabowski <art@openbsd.org> + * Copyright (c) 2004 Aaron Campbell <aaron@openbsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/evcount.h> +#include <sys/timeout.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/sysctl.h> + +#ifdef __HAVE_EVCOUNT + +static TAILQ_HEAD(,evcount) evcount_list; +static struct evcount *evcount_next_sync; + +/* + * Standard evcount parents. + */ +struct evcount evcount_intr; + +void evcount_timeout(void *); +void evcount_init(void); +void evcount_sync(struct evcount *); + +void +evcount_init(void) +{ +#ifndef __LP64__ + static struct timeout ec_to; + + timeout_set(&ec_to, evcount_timeout, &ec_to); + timeout_add(&ec_to, hz); +#endif + TAILQ_INIT(&evcount_list); + + evcount_attach(&evcount_intr, "intr", NULL, NULL); +} + + +void +evcount_attach(ec, name, data, parent) + struct evcount *ec; + const char *name; + void *data; + struct evcount *parent; +{ + static int nextid = 0; + + if (nextid == 0) { + nextid++; /* start with 1 */ + evcount_init(); + } + + memset(ec, 0, sizeof(*ec)); + ec->ec_name = name; + ec->ec_parent = parent; + ec->ec_id = nextid++; + ec->ec_data = data; + TAILQ_INSERT_TAIL(&evcount_list, ec, next); +} + +void +evcount_detach(ec) + struct evcount *ec; +{ + if (evcount_next_sync == ec) + evcount_next_sync = TAILQ_NEXT(ec, next); + + TAILQ_REMOVE(&evcount_list, ec, next); +} + +int +evcount_sysctl(name, namelen, oldp, oldlenp, newp, newlen) + int *name; + u_int namelen; + void *oldp; + size_t *oldlenp; + void *newp; + size_t newlen; +{ + struct evcount *ec; + int error = 0; + int nintr, i; + + if (newp != NULL) + return (EPERM); + + if (name[0] != KERN_INTRCNT_NUM) { + if (namelen != 2) + return (ENOTDIR); + if (name[1] < 0) + return (EINVAL); + i = name[1]; + } else + i = -1; + + nintr = 0; + TAILQ_FOREACH(ec, &evcount_list, next) { + if (ec->ec_parent != &evcount_intr) + continue; + if (nintr++ == i) + break; + } + + switch (name[0]) { + case KERN_INTRCNT_NUM: + error = sysctl_rdint(oldp, oldlenp, NULL, nintr); + break; + case KERN_INTRCNT_CNT: + if (ec == NULL) + return (ENOENT); + /* XXX - bogus cast to int, but we can't do better. */ + error = sysctl_rdint(oldp, oldlenp, NULL, (int)ec->ec_count); + break; + case KERN_INTRCNT_NAME: + if (ec == NULL) + return (ENOENT); + error = sysctl_rdstring(oldp, oldlenp, NULL, ec->ec_name); + break; + case KERN_INTRCNT_VECTOR: + if (ec == NULL || ec->ec_data == NULL) + return (ENOENT); + error = sysctl_rdint(oldp, oldlenp, NULL, + *((int *)ec->ec_data)); + break; + default: + error = EOPNOTSUPP; + break; + } + + return (error); +} + +#ifndef __LP64__ +/* + * This timeout has to run once in a while for every event counter to + * sync the real 64 bit counter with the 32 bit temporary counter, because + * we cannot atomically increment the 64 bit counter on 32 bit systems. + */ +void +evcount_timeout(void *v) +{ + struct timeout *to = v; + + if (evcount_next_sync == NULL) + evcount_next_sync = TAILQ_FIRST(&evcount_list); + + evcount_sync(evcount_next_sync); + evcount_next_sync = TAILQ_NEXT(evcount_next_sync, next); + + timeout_add(to, hz); +} +#endif + +void +evcount_sync(struct evcount *ec) +{ +#ifndef __LP64__ + ec->ec_count += ec->ec_count32; + ec->ec_count32 = 0; +#endif +} + +#endif /* __HAVE_EVCOUNT */ diff --git a/sys/sys/evcount.h b/sys/sys/evcount.h new file mode 100644 index 00000000000..98529e15f54 --- /dev/null +++ b/sys/sys/evcount.h @@ -0,0 +1,59 @@ +/* $OpenBSD: evcount.h,v 1.1 2004/06/28 01:34:46 aaron Exp $ */ +/* + * Copyright (c) 2004 Artur Grabowski <art@openbsd.org> + * Copyright (c) 2004 Aaron Campbell <aaron@openbsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __SYS_EVCOUNT_H__ +#define __SYS_EVCOUNT_H__ + +#ifdef _KERNEL + +#include <sys/queue.h> + +struct evcount { + u_int64_t ec_count; /* main counter */ +#ifndef __LP64__ + u_int32_t ec_count32; /* temporary 32-bit counter */ +#endif + int ec_id; /* counter ID */ + const char *ec_name; /* counter name */ + struct evcount *ec_parent; /* parent */ + void *ec_data; /* user data */ + + TAILQ_ENTRY(evcount) next; +}; + +void evcount_attach(struct evcount *, const char *, void *, struct evcount *); +void evcount_detach(struct evcount *); +int evcount_sysctl(int *, u_int, void *, size_t *, void *, size_t); + +/* + * Standard evcount parents. + */ +extern struct evcount evcount_intr; + +#endif /* _KERNEL */ + +#endif diff --git a/sys/sys/sysctl.h b/sys/sys/sysctl.h index f37d99ac0e6..9afc78a8655 100644 --- a/sys/sys/sysctl.h +++ b/sys/sys/sysctl.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sysctl.h,v 1.78 2004/06/11 01:32:05 deraadt Exp $ */ +/* $OpenBSD: sysctl.h,v 1.79 2004/06/28 01:34:46 aaron Exp $ */ /* $NetBSD: sysctl.h,v 1.16 1996/04/09 20:55:36 cgd Exp $ */ /* @@ -180,7 +180,8 @@ struct ctlname { #define KERN_EMUL 65 /* node: emuls */ #define KERN_PROC2 66 /* struct: process entries */ #define KERN_MAXCLUSTERS 67 /* number of mclusters */ -#define KERN_MAXID 68 /* number of valid kern ids */ +#define KERN_EVCOUNT 68 /* node: event counters */ +#define KERN_MAXID 69 /* number of valid kern ids */ #define CTL_KERN_NAMES { \ { 0, 0 }, \ @@ -251,6 +252,7 @@ struct ctlname { { "emul", CTLTYPE_NODE }, \ { "proc2", CTLTYPE_STRUCT }, \ { "maxclusters", CTLTYPE_INT }, \ + { "evcount", CTLTYPE_NODE }, \ } /* @@ -454,12 +456,13 @@ struct kinfo_proc2 { }; /* - * KERN_INTR_CNT + * KERN_INTRCNT */ #define KERN_INTRCNT_NUM 1 /* int: # intrcnt */ #define KERN_INTRCNT_CNT 2 /* node: intrcnt */ #define KERN_INTRCNT_NAME 3 /* node: names */ -#define KERN_INTRCNT_MAXID 4 +#define KERN_INTRCNT_VECTOR 4 /* node: interrupt vector # */ +#define KERN_INTRCNT_MAXID 5 #define CTL_KERN_INTRCNT_NAMES { \ { 0, 0 }, \ |