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 */ 28 29 #include <sys/param.h> 30 #include <sys/queue.h> 31 #include <sys/malloc.h> 32 #include <sys/kernel.h> 33 #include <sys/module.h> 34 #include <sys/errno.h> 35 #include <sys/thread.h> 36 #include <sys/thread2.h> 37 #ifndef TEST 38 #include <sys/systm.h> 39 #endif 40 #include <sys/kobj.h> 41 42 #ifdef TEST 43 #include "usertest.h" 44 #endif 45 46 static MALLOC_DEFINE(M_KOBJ, "kobj", "Kernel object structures"); 47 48 static struct lwkt_token kobj_token; 49 static int kobj_next_id = 1; 50 51 static void 52 kobj_init_token(void *arg) 53 { 54 lwkt_token_init(&kobj_token, "kobj"); 55 } 56 57 SYSINIT(kobj, SI_BOOT1_LOCK, SI_ORDER_ANY, kobj_init_token, NULL); 58 59 /* 60 * This method structure is used to initialise new caches. Since the 61 * desc pointer is NULL, it is guaranteed never to match any real 62 * descriptors. 63 */ 64 static const struct kobj_method null_method = { 65 0, 0, 66 }; 67 68 int 69 kobj_error_method(void) 70 { 71 return ENXIO; 72 } 73 74 static void 75 kobj_register_method(struct kobjop_desc *desc) 76 { 77 if (desc->id == 0) 78 desc->id = kobj_next_id++; 79 } 80 81 static void 82 kobj_unregister_method(struct kobjop_desc *desc) 83 { 84 } 85 86 static void 87 kobj_class_compile(kobj_class_t cls) 88 { 89 kobj_method_t *m; 90 kobj_ops_t ops; 91 int i; 92 93 /* 94 * Don't do anything if we are already compiled. 95 */ 96 if (cls->ops) 97 return; 98 99 /* 100 * Allocate space for the compiled ops table. 101 */ 102 ops = kmalloc(sizeof(struct kobj_ops), M_KOBJ, M_INTWAIT); 103 for (i = 0; i < KOBJ_CACHE_SIZE; i++) 104 ops->cache[i] = &null_method; 105 if (cls->ops) { 106 /* 107 * In case of preemption, another thread might have been faster, 108 * but that's fine for us. 109 */ 110 if (ops) 111 kfree(ops, M_KOBJ); 112 return; 113 } 114 115 if (!ops) 116 panic("kobj_compile_methods: out of memory"); 117 118 ops->cls = cls; 119 cls->ops = ops; 120 121 /* 122 * Afterwards register any methods which need it. 123 */ 124 for (m = cls->methods; m->desc; m++) 125 kobj_register_method(m->desc); 126 } 127 128 static kobj_method_t * 129 kobj_lookup_method_class(kobj_class_t cls, kobjop_desc_t desc) 130 { 131 kobj_method_t *methods = cls->methods; 132 kobj_method_t *ce; 133 134 for (ce = methods; ce && ce->desc; ce++) 135 if (ce->desc == desc) 136 return(ce); 137 138 return(0); 139 } 140 141 static kobj_method_t * 142 kobj_lookup_method_mi(kobj_class_t cls, kobjop_desc_t desc) 143 { 144 kobj_method_t *ce; 145 kobj_class_t *basep; 146 147 ce = kobj_lookup_method_class(cls, desc); 148 if (ce) 149 return(ce); 150 151 basep = cls->baseclasses; 152 if (basep) { 153 for (; *basep; basep++) { 154 ce = kobj_lookup_method_mi(*basep, desc); 155 if (ce) 156 return(ce); 157 } 158 } 159 160 return(0); 161 } 162 163 kobj_method_t* 164 kobj_lookup_method(kobj_class_t cls, 165 kobj_method_t **cep, 166 kobjop_desc_t desc) 167 { 168 kobj_method_t *ce; 169 170 ce = kobj_lookup_method_mi(cls, desc); 171 if (!ce) 172 ce = &desc->deflt; 173 *cep = ce; 174 return(ce); 175 } 176 177 /* 178 * This is called from the KOBJOPLOOKUP() macro in sys/kobj.h and 179 * replaces the original large body of the macro with a single 180 * procedure call. 181 */ 182 kobjop_t 183 kobj_lookup_method_cache(kobj_class_t cls, kobj_method_t **cep, 184 kobjop_desc_t desc) 185 { 186 kobj_method_t *ce; 187 188 cep = &cep[desc->id & (KOBJ_CACHE_SIZE-1)]; 189 ce = *cep; 190 if (ce->desc != desc) 191 ce = kobj_lookup_method(cls, cep, desc); 192 return(ce->func); 193 } 194 195 static void 196 kobj_class_free(kobj_class_t cls) 197 { 198 int i; 199 kobj_method_t *m; 200 201 /* 202 * Unregister any methods which are no longer used. 203 */ 204 for (i = 0, m = cls->methods; m->desc; i++, m++) 205 kobj_unregister_method(m->desc); 206 207 /* 208 * Free memory and clean up. 209 */ 210 kfree(cls->ops, M_KOBJ); 211 cls->ops = 0; 212 } 213 214 void 215 kobj_class_instantiate(kobj_class_t cls) 216 { 217 lwkt_gettoken(&kobj_token); 218 crit_enter(); 219 220 if (!cls->ops) 221 kobj_class_compile(cls); 222 cls->refs++; 223 224 crit_exit(); 225 lwkt_reltoken(&kobj_token); 226 } 227 228 void 229 kobj_class_uninstantiate(kobj_class_t cls) 230 { 231 lwkt_gettoken(&kobj_token); 232 crit_enter(); 233 234 cls->refs--; 235 if (cls->refs == 0) 236 kobj_class_free(cls); 237 238 crit_exit(); 239 lwkt_reltoken(&kobj_token); 240 } 241 242 kobj_t 243 kobj_create(kobj_class_t cls, 244 struct malloc_type *mtype, 245 int mflags) 246 { 247 kobj_t obj; 248 249 /* 250 * Allocate and initialise the new object. 251 */ 252 obj = kmalloc(cls->size, mtype, mflags | M_ZERO); 253 if (!obj) 254 return 0; 255 kobj_init(obj, cls); 256 257 return obj; 258 } 259 260 void 261 kobj_init(kobj_t obj, kobj_class_t cls) 262 { 263 kobj_class_instantiate(cls); 264 obj->ops = cls->ops; 265 } 266 267 void 268 kobj_delete(kobj_t obj, struct malloc_type *mtype) 269 { 270 kobj_class_t cls = obj->ops->cls; 271 272 kobj_class_uninstantiate(cls); 273 274 obj->ops = 0; 275 if (mtype) 276 kfree(obj, mtype); 277 } 278