1 /* $OpenBSD: subr_evcount.c,v 1.8 2006/10/17 10:29:50 grange Exp $ */ 2 /* 3 * Copyright (c) 2004 Artur Grabowski <art@openbsd.org> 4 * Copyright (c) 2004 Aaron Campbell <aaron@openbsd.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 17 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 18 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 19 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <sys/param.h> 29 #include <sys/evcount.h> 30 #include <sys/timeout.h> 31 #include <sys/kernel.h> 32 #include <sys/systm.h> 33 #include <sys/sysctl.h> 34 35 static TAILQ_HEAD(,evcount) evcount_list; 36 37 /* 38 * Standard evcount parents. 39 */ 40 struct evcount evcount_intr; 41 42 void evcount_init(void); 43 44 void 45 evcount_init(void) 46 { 47 TAILQ_INIT(&evcount_list); 48 49 evcount_attach(&evcount_intr, "intr", NULL, NULL); 50 } 51 52 53 void 54 evcount_attach(struct evcount *ec, const char *name, void *data, 55 struct evcount *parent) 56 { 57 static int nextid = 0; 58 59 if (nextid == 0) { 60 nextid++; /* start with 1 */ 61 evcount_init(); 62 } 63 64 memset(ec, 0, sizeof(*ec)); 65 ec->ec_name = name; 66 ec->ec_parent = parent; 67 ec->ec_id = nextid++; 68 ec->ec_data = data; 69 TAILQ_INSERT_TAIL(&evcount_list, ec, next); 70 } 71 72 void 73 evcount_detach(struct evcount *ec) 74 { 75 TAILQ_REMOVE(&evcount_list, ec, next); 76 } 77 78 #ifndef SMALL_KERNEL 79 80 int 81 evcount_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, 82 void *newp, size_t newlen) 83 { 84 int error = 0, s, nintr, i; 85 struct evcount *ec; 86 u_int64_t count; 87 88 if (newp != NULL) 89 return (EPERM); 90 91 if (name[0] != KERN_INTRCNT_NUM) { 92 if (namelen != 2) 93 return (ENOTDIR); 94 if (name[1] < 0) 95 return (EINVAL); 96 i = name[1]; 97 } else 98 i = -1; 99 100 nintr = 0; 101 TAILQ_FOREACH(ec, &evcount_list, next) { 102 if (ec->ec_parent != &evcount_intr) 103 continue; 104 if (nintr++ == i) 105 break; 106 } 107 108 switch (name[0]) { 109 case KERN_INTRCNT_NUM: 110 error = sysctl_rdint(oldp, oldlenp, NULL, nintr); 111 break; 112 case KERN_INTRCNT_CNT: 113 if (ec == NULL) 114 return (ENOENT); 115 s = splhigh(); 116 count = ec->ec_count; 117 splx(s); 118 error = sysctl_rdquad(oldp, oldlenp, NULL, count); 119 break; 120 case KERN_INTRCNT_NAME: 121 if (ec == NULL) 122 return (ENOENT); 123 error = sysctl_rdstring(oldp, oldlenp, NULL, ec->ec_name); 124 break; 125 case KERN_INTRCNT_VECTOR: 126 if (ec == NULL || ec->ec_data == NULL) 127 return (ENOENT); 128 error = sysctl_rdint(oldp, oldlenp, NULL, 129 *((int *)ec->ec_data)); 130 break; 131 default: 132 error = EOPNOTSUPP; 133 break; 134 } 135 136 return (error); 137 } 138 #endif /* SMALL_KERNEL */ 139