subr_kobj.c revision 118921
1204431Sraj/*- 2204431Sraj * Copyright (c) 2000 Doug Rabson 3204431Sraj * All rights reserved. 4204431Sraj * 5204431Sraj * Redistribution and use in source and binary forms, with or without 6204431Sraj * modification, are permitted provided that the following conditions 7204431Sraj * are met: 8204431Sraj * 1. Redistributions of source code must retain the above copyright 9204431Sraj * notice, this list of conditions and the following disclaimer. 10204431Sraj * 2. Redistributions in binary form must reproduce the above copyright 11204431Sraj * notice, this list of conditions and the following disclaimer in the 12204431Sraj * documentation and/or other materials provided with the distribution. 13204431Sraj * 14204431Sraj * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15204431Sraj * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16204431Sraj * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17204431Sraj * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18204431Sraj * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19204431Sraj * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20204431Sraj * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21204431Sraj * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22204431Sraj * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23204431Sraj * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24204431Sraj * SUCH DAMAGE. 25204431Sraj */ 26204431Sraj 27204431Sraj#include <sys/cdefs.h> 28204431Sraj__FBSDID("$FreeBSD: head/sys/kern/subr_kobj.c 118921 2003-08-14 21:16:46Z cg $"); 29204431Sraj 30204431Sraj#include <sys/param.h> 31204431Sraj#include <sys/queue.h> 32204431Sraj#include <sys/malloc.h> 33204431Sraj#include <sys/kernel.h> 34204431Sraj#include <sys/module.h> 35204431Sraj#include <sys/errno.h> 36204431Sraj#include <sys/sysctl.h> 37204431Sraj#ifndef TEST 38204431Sraj#include <sys/systm.h> 39204431Sraj#endif 40204431Sraj#include <sys/kobj.h> 41204431Sraj 42204431Sraj#ifdef TEST 43204431Sraj#include "usertest.h" 44204431Sraj#endif 45204431Sraj 46204431Srajstatic MALLOC_DEFINE(M_KOBJ, "kobj", "Kernel object structures"); 47204431Sraj 48204431Sraj#ifdef KOBJ_STATS 49204431Sraj 50204431Sraju_int kobj_lookup_hits; 51204431Sraju_int kobj_lookup_misses; 52204431Sraj 53204431SrajSYSCTL_UINT(_kern, OID_AUTO, kobj_hits, CTLFLAG_RD, 54204431Sraj &kobj_lookup_hits, 0, ""); 55204431SrajSYSCTL_UINT(_kern, OID_AUTO, kobj_misses, CTLFLAG_RD, 56204431Sraj &kobj_lookup_misses, 0, ""); 57204431Sraj 58204431Sraj#endif 59204431Sraj 60204431Srajstatic int kobj_next_id = 1; 61204431Sraj 62204431SrajSYSCTL_UINT(_kern, OID_AUTO, kobj_methodcount, CTLFLAG_RD, 63204431Sraj &kobj_next_id, 0, ""); 64204431Sraj 65204431Srajstatic int 66204431Srajkobj_error_method(void) 67204431Sraj{ 68204431Sraj return ENXIO; 69204431Sraj} 70204431Sraj 71204431Srajstatic void 72204431Srajkobj_register_method(struct kobjop_desc *desc) 73204431Sraj{ 74204431Sraj if (desc->id == 0) { 75204431Sraj KASSERT((kobj_next_id < KOBJ_CACHE_SIZE), ("kobj method table overflow")); 76204431Sraj desc->id = kobj_next_id++; 77204433Sraj } 78204431Sraj} 79204431Sraj 80204431Srajstatic void 81204431Srajkobj_unregister_method(struct kobjop_desc *desc) 82204431Sraj{ 83204431Sraj} 84204431Sraj 85204431Srajstatic void 86204431Srajkobj_class_compile_common(kobj_class_t cls, kobj_ops_t ops) 87204431Sraj{ 88204431Sraj kobj_method_t *m; 89204431Sraj int i; 90204431Sraj 91204431Sraj /* 92204431Sraj * Don't do anything if we are already compiled. 93204433Sraj */ 94204431Sraj if (cls->ops) 95266130Sian return; 96204431Sraj 97204433Sraj /* 98204431Sraj * First register any methods which need it. 99204431Sraj */ 100204433Sraj for (i = 0, m = cls->methods; m->desc; i++, m++) 101204431Sraj kobj_register_method(m->desc); 102204433Sraj 103204431Sraj /* 104204431Sraj * Then initialise the ops table. 105204431Sraj */ 106204431Sraj bzero(ops, sizeof(struct kobj_ops)); 107204433Sraj ops->cls = cls; 108204431Sraj cls->ops = ops; 109204431Sraj} 110204431Sraj 111204431Srajvoid 112204431Srajkobj_class_compile(kobj_class_t cls) 113204431Sraj{ 114204433Sraj kobj_ops_t ops; 115204433Sraj 116204431Sraj /* 117204433Sraj * Allocate space for the compiled ops table. 118204431Sraj */ 119204431Sraj ops = malloc(sizeof(struct kobj_ops), M_KOBJ, M_NOWAIT); 120204433Sraj if (!ops) 121204433Sraj panic("kobj_compile_methods: out of memory"); 122204433Sraj kobj_class_compile_common(cls, ops); 123204433Sraj} 124204433Sraj 125204431Srajvoid 126204433Srajkobj_class_compile_static(kobj_class_t cls, kobj_ops_t ops) 127204433Sraj{ 128204433Sraj /* 129204433Sraj * Increment refs to make sure that the ops table is not freed. 130204433Sraj */ 131204433Sraj cls->refs++; 132204433Sraj kobj_class_compile_common(cls, ops); 133204433Sraj} 134204431Sraj 135204431Srajvoid 136204433Srajkobj_lookup_method(kobj_method_t *methods, 137204433Sraj kobj_method_t *ce, 138204431Sraj kobjop_desc_t desc) 139204433Sraj{ 140204431Sraj ce->desc = desc; 141204431Sraj for (; methods && methods->desc; methods++) { 142204431Sraj if (methods->desc == desc) { 143204431Sraj ce->func = methods->func; 144204431Sraj return; 145204431Sraj } 146204431Sraj } 147204431Sraj if (desc->deflt) 148204431Sraj ce->func = desc->deflt; 149204431Sraj else 150204431Sraj ce->func = kobj_error_method; 151204431Sraj return; 152238742Simp} 153238742Simp 154238742Simpvoid 155238742Simpkobj_class_free(kobj_class_t cls) 156238742Simp{ 157238742Simp int i; 158238742Simp kobj_method_t *m; 159238742Simp 160238742Simp /* 161204431Sraj * Unregister any methods which are no longer used. 162204431Sraj */ 163204431Sraj for (i = 0, m = cls->methods; m->desc; i++, m++) 164204431Sraj kobj_unregister_method(m->desc); 165204431Sraj 166204431Sraj /* 167204431Sraj * Free memory and clean up. 168204431Sraj */ 169204431Sraj free(cls->ops, M_KOBJ); 170204431Sraj cls->ops = 0; 171204431Sraj} 172204431Sraj 173204431Srajkobj_t 174204431Srajkobj_create(kobj_class_t cls, 175204431Sraj struct malloc_type *mtype, 176204431Sraj int mflags) 177204431Sraj{ 178204431Sraj kobj_t obj; 179204431Sraj 180204431Sraj /* 181204431Sraj * Allocate and initialise the new object. 182204431Sraj */ 183204431Sraj obj = malloc(cls->size, mtype, mflags | M_ZERO); 184204431Sraj if (!obj) 185204433Sraj return 0; 186204433Sraj kobj_init(obj, cls); 187204431Sraj 188204431Sraj return obj; 189204431Sraj} 190204433Sraj 191204433Srajvoid 192204433Srajkobj_init(kobj_t obj, kobj_class_t cls) 193204433Sraj{ 194204433Sraj /* 195204431Sraj * Consider compiling the class' method table. 196204431Sraj */ 197204431Sraj if (!cls->ops) 198204431Sraj kobj_class_compile(cls); 199204431Sraj 200204431Sraj obj->ops = cls->ops; 201266130Sian cls->refs++; 202266130Sian} 203266130Sian 204266130Sianvoid 205266130Siankobj_delete(kobj_t obj, struct malloc_type *mtype) 206266130Sian{ 207266130Sian kobj_class_t cls = obj->ops->cls; 208266130Sian 209266130Sian /* 210266130Sian * Consider freeing the compiled method table for the class 211266130Sian * after its last instance is deleted. As an optimisation, we 212266130Sian * should defer this for a short while to avoid thrashing. 213266130Sian */ 214266130Sian cls->refs--; 215266130Sian if (!cls->refs) 216266130Sian kobj_class_free(cls); 217266130Sian 218266130Sian obj->ops = 0; 219266130Sian if (mtype) 220266130Sian free(obj, mtype); 221266130Sian} 222266130Sian