1 /* $OpenBSD: subr_evcount.c,v 1.4 2004/09/29 07:37:04 miod 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 #ifdef __HAVE_EVCOUNT 36 37 static TAILQ_HEAD(,evcount) evcount_list; 38 static struct evcount *evcount_next_sync; 39 40 /* 41 * Standard evcount parents. 42 */ 43 struct evcount evcount_intr; 44 45 void evcount_timeout(void *); 46 void evcount_init(void); 47 48 void 49 evcount_init(void) 50 { 51 TAILQ_INIT(&evcount_list); 52 53 evcount_attach(&evcount_intr, "intr", NULL, NULL); 54 } 55 56 57 void 58 evcount_attach(ec, name, data, parent) 59 struct evcount *ec; 60 const char *name; 61 void *data; 62 struct evcount *parent; 63 { 64 static int nextid = 0; 65 66 if (nextid == 0) { 67 nextid++; /* start with 1 */ 68 evcount_init(); 69 } 70 71 memset(ec, 0, sizeof(*ec)); 72 ec->ec_name = name; 73 ec->ec_parent = parent; 74 ec->ec_id = nextid++; 75 ec->ec_data = data; 76 TAILQ_INSERT_TAIL(&evcount_list, ec, next); 77 } 78 79 void 80 evcount_detach(ec) 81 struct evcount *ec; 82 { 83 if (evcount_next_sync == ec) 84 evcount_next_sync = TAILQ_NEXT(ec, next); 85 86 TAILQ_REMOVE(&evcount_list, ec, next); 87 } 88 89 int 90 evcount_sysctl(name, namelen, oldp, oldlenp, newp, newlen) 91 int *name; 92 u_int namelen; 93 void *oldp; 94 size_t *oldlenp; 95 void *newp; 96 size_t newlen; 97 { 98 int error = 0, s, nintr, i; 99 struct evcount *ec; 100 u_int64_t count; 101 102 if (newp != NULL) 103 return (EPERM); 104 105 if (name[0] != KERN_INTRCNT_NUM) { 106 if (namelen != 2) 107 return (ENOTDIR); 108 if (name[1] < 0) 109 return (EINVAL); 110 i = name[1]; 111 } else 112 i = -1; 113 114 nintr = 0; 115 TAILQ_FOREACH(ec, &evcount_list, next) { 116 if (ec->ec_parent != &evcount_intr) 117 continue; 118 if (nintr++ == i) 119 break; 120 } 121 122 switch (name[0]) { 123 case KERN_INTRCNT_NUM: 124 error = sysctl_rdint(oldp, oldlenp, NULL, nintr); 125 break; 126 case KERN_INTRCNT_CNT: 127 if (ec == NULL) 128 return (ENOENT); 129 s = splhigh(); 130 count = ec->ec_count; 131 splx(s); 132 error = sysctl_rdquad(oldp, oldlenp, NULL, count); 133 break; 134 case KERN_INTRCNT_NAME: 135 if (ec == NULL) 136 return (ENOENT); 137 error = sysctl_rdstring(oldp, oldlenp, NULL, ec->ec_name); 138 break; 139 case KERN_INTRCNT_VECTOR: 140 if (ec == NULL || ec->ec_data == NULL) 141 return (ENOENT); 142 error = sysctl_rdint(oldp, oldlenp, NULL, 143 *((int *)ec->ec_data)); 144 break; 145 default: 146 error = EOPNOTSUPP; 147 break; 148 } 149 150 return (error); 151 } 152 153 #endif /* __HAVE_EVCOUNT */ 154