1 /*- 2 * Copyright (c) 2000 Doug Rabson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: src/sys/kern/subr_kobj.c,v 1.4.2.1 2001/02/02 19:49:13 cg Exp $ 27 * $DragonFly: src/sys/kern/subr_kobj.c,v 1.9 2007/04/30 07:18:54 dillon Exp $ 28 */ 29 30 #include <sys/param.h> 31 #include <sys/queue.h> 32 #include <sys/malloc.h> 33 #include <sys/kernel.h> 34 #include <sys/module.h> 35 #include <sys/errno.h> 36 #include <sys/thread.h> 37 #include <sys/thread2.h> 38 #ifndef TEST 39 #include <sys/systm.h> 40 #endif 41 #include <sys/kobj.h> 42 43 #ifdef TEST 44 #include "usertest.h" 45 #endif 46 47 static MALLOC_DEFINE(M_KOBJ, "kobj", "Kernel object structures"); 48 49 #ifdef KOBJ_STATS 50 51 #include <sys/sysctl.h> 52 53 u_int kobj_lookup_hits; 54 u_int kobj_lookup_misses; 55 56 SYSCTL_UINT(_kern, OID_AUTO, kobj_hits, CTLFLAG_RD, 57 &kobj_lookup_hits, 0, "") 58 SYSCTL_UINT(_kern, OID_AUTO, kobj_misses, CTLFLAG_RD, 59 &kobj_lookup_misses, 0, "") 60 61 #endif 62 63 static struct lwkt_token kobj_token; 64 static int kobj_next_id = 1; 65 66 static void 67 kobj_init_token(void *arg) 68 { 69 lwkt_token_init(&kobj_token); 70 } 71 72 SYSINIT(kobj, SI_BOOT1_LOCK, SI_ORDER_ANY, kobj_init_token, NULL); 73 74 /* 75 * This method structure is used to initialise new caches. Since the 76 * desc pointer is NULL, it is guaranteed never to match any real 77 * descriptors. 78 */ 79 static struct kobj_method null_method = { 80 0, 0, 81 }; 82 83 int 84 kobj_error_method(void) 85 { 86 return ENXIO; 87 } 88 89 static void 90 kobj_register_method(struct kobjop_desc *desc) 91 { 92 if (desc->id == 0) 93 desc->id = kobj_next_id++; 94 } 95 96 static void 97 kobj_unregister_method(struct kobjop_desc *desc) 98 { 99 } 100 101 static void 102 kobj_class_compile(kobj_class_t cls) 103 { 104 kobj_method_t *m; 105 kobj_ops_t ops; 106 int i; 107 108 /* 109 * Don't do anything if we are already compiled. 110 */ 111 if (cls->ops) 112 return; 113 114 /* 115 * Allocate space for the compiled ops table. 116 */ 117 ops = kmalloc(sizeof(struct kobj_ops), M_KOBJ, M_INTWAIT); 118 for (i = 0; i < KOBJ_CACHE_SIZE; i++) 119 ops->cache[i] = &null_method; 120 if (cls->ops) { 121 /* 122 * In case of preemption, another thread might have been faster, 123 * but that's fine for us. 124 */ 125 if (ops) 126 kfree(ops, M_KOBJ); 127 return; 128 } 129 130 if (!ops) 131 panic("kobj_compile_methods: out of memory"); 132 133 ops->cls = cls; 134 cls->ops = ops; 135 136 /* 137 * Afterwards register any methods which need it. 138 */ 139 for (m = cls->methods; m->desc; m++) 140 kobj_register_method(m->desc); 141 } 142 143 static kobj_method_t * 144 kobj_lookup_method_class(kobj_class_t cls, kobjop_desc_t desc) 145 { 146 kobj_method_t *methods = cls->methods; 147 kobj_method_t *ce; 148 149 for (ce = methods; ce && ce->desc; ce++) 150 if (ce->desc == desc) 151 return(ce); 152 153 return(0); 154 } 155 156 static kobj_method_t * 157 kobj_lookup_method_mi(kobj_class_t cls, kobjop_desc_t desc) 158 { 159 kobj_method_t *ce; 160 kobj_class_t *basep; 161 162 ce = kobj_lookup_method_class(cls, desc); 163 if (ce) 164 return(ce); 165 166 basep = cls->baseclasses; 167 if (basep) { 168 for (; *basep; basep++) { 169 ce = kobj_lookup_method_mi(*basep, desc); 170 if (ce) 171 return(ce); 172 } 173 } 174 175 return(0); 176 } 177 178 kobj_method_t* 179 kobj_lookup_method(kobj_class_t cls, 180 kobj_method_t **cep, 181 kobjop_desc_t desc) 182 { 183 kobj_method_t *ce; 184 185 #ifdef KOBJ_STATS 186 /* 187 * Correct for the 'hit' assumption in KOBJOPLOOKUP and record 188 * a 'miss'. 189 */ 190 kobj_lookup_hits--; 191 kobj_lookup_misses--; 192 #endif 193 194 ce = kobj_lookup_method_mi(cls, desc); 195 if (!ce) 196 ce = desc->deflt; 197 *cep = ce; 198 return(ce); 199 } 200 201 static void 202 kobj_class_free(kobj_class_t cls) 203 { 204 int i; 205 kobj_method_t *m; 206 207 /* 208 * Unregister any methods which are no longer used. 209 */ 210 for (i = 0, m = cls->methods; m->desc; i++, m++) 211 kobj_unregister_method(m->desc); 212 213 /* 214 * Free memory and clean up. 215 */ 216 kfree(cls->ops, M_KOBJ); 217 cls->ops = 0; 218 } 219 220 void 221 kobj_class_instantiate(kobj_class_t cls) 222 { 223 lwkt_tokref ilock; 224 225 lwkt_gettoken(&ilock, &kobj_token); 226 crit_enter(); 227 228 if (!cls->ops) 229 kobj_class_compile(cls); 230 cls->refs++; 231 232 crit_exit(); 233 lwkt_reltoken(&ilock); 234 } 235 236 void 237 kobj_class_uninstantiate(kobj_class_t cls) 238 { 239 lwkt_tokref ilock; 240 241 lwkt_gettoken(&ilock, &kobj_token); 242 crit_enter(); 243 244 cls->refs--; 245 if (cls->refs == 0) 246 kobj_class_free(cls); 247 248 crit_exit(); 249 lwkt_reltoken(&ilock); 250 } 251 252 kobj_t 253 kobj_create(kobj_class_t cls, 254 struct malloc_type *mtype, 255 int mflags) 256 { 257 kobj_t obj; 258 259 /* 260 * Allocate and initialise the new object. 261 */ 262 obj = kmalloc(cls->size, mtype, mflags | M_ZERO); 263 if (!obj) 264 return 0; 265 kobj_init(obj, cls); 266 267 return obj; 268 } 269 270 void 271 kobj_init(kobj_t obj, kobj_class_t cls) 272 { 273 kobj_class_instantiate(cls); 274 obj->ops = cls->ops; 275 } 276 277 void 278 kobj_delete(kobj_t obj, struct malloc_type *mtype) 279 { 280 kobj_class_t cls = obj->ops->cls; 281 282 kobj_class_uninstantiate(cls); 283 284 obj->ops = 0; 285 if (mtype) 286 kfree(obj, mtype); 287 } 288