summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Campbell <aaron@cvs.openbsd.org>2004-06-28 01:34:47 +0000
committerAaron Campbell <aaron@cvs.openbsd.org>2004-06-28 01:34:47 +0000
commitfb8afb0fc41ef3fe4cd5cc7bdb475fd4156c546f (patch)
treef74d6135fb63cd5fe8ab0273bc96c8d8e61ce444
parent41dde1384131189f656d524751329b4be86e4de1 (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/files3
-rw-r--r--sys/kern/kern_sysctl.c17
-rw-r--r--sys/kern/subr_evcount.c188
-rw-r--r--sys/sys/evcount.h59
-rw-r--r--sys/sys/sysctl.h11
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 }, \