subr_kobj.c revision 118921
159093Sdfr/*- 259093Sdfr * Copyright (c) 2000 Doug Rabson 359093Sdfr * All rights reserved. 459093Sdfr * 559093Sdfr * Redistribution and use in source and binary forms, with or without 659093Sdfr * modification, are permitted provided that the following conditions 759093Sdfr * are met: 859093Sdfr * 1. Redistributions of source code must retain the above copyright 959093Sdfr * notice, this list of conditions and the following disclaimer. 1059093Sdfr * 2. Redistributions in binary form must reproduce the above copyright 1159093Sdfr * notice, this list of conditions and the following disclaimer in the 1259093Sdfr * documentation and/or other materials provided with the distribution. 1359093Sdfr * 1459093Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1559093Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1659093Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1759093Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1859093Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1959093Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2059093Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2159093Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2259093Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2359093Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2459093Sdfr * SUCH DAMAGE. 2559093Sdfr */ 2659093Sdfr 27116182Sobrien#include <sys/cdefs.h> 28116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/subr_kobj.c 118921 2003-08-14 21:16:46Z cg $"); 29116182Sobrien 3059093Sdfr#include <sys/param.h> 3159093Sdfr#include <sys/queue.h> 3259093Sdfr#include <sys/malloc.h> 3359093Sdfr#include <sys/kernel.h> 3459093Sdfr#include <sys/module.h> 3559093Sdfr#include <sys/errno.h> 36118921Scg#include <sys/sysctl.h> 3759093Sdfr#ifndef TEST 3859093Sdfr#include <sys/systm.h> 3959093Sdfr#endif 4059093Sdfr#include <sys/kobj.h> 4159093Sdfr 4259093Sdfr#ifdef TEST 4359093Sdfr#include "usertest.h" 4459093Sdfr#endif 4559093Sdfr 4659093Sdfrstatic MALLOC_DEFINE(M_KOBJ, "kobj", "Kernel object structures"); 4759093Sdfr 4859093Sdfr#ifdef KOBJ_STATS 4959093Sdfr 5098105Skbyancu_int kobj_lookup_hits; 5198105Skbyancu_int kobj_lookup_misses; 5259093Sdfr 5398105SkbyancSYSCTL_UINT(_kern, OID_AUTO, kobj_hits, CTLFLAG_RD, 54118921Scg &kobj_lookup_hits, 0, ""); 5598105SkbyancSYSCTL_UINT(_kern, OID_AUTO, kobj_misses, CTLFLAG_RD, 56118921Scg &kobj_lookup_misses, 0, ""); 5759093Sdfr 5859093Sdfr#endif 5959093Sdfr 6059093Sdfrstatic int kobj_next_id = 1; 6159093Sdfr 62118921ScgSYSCTL_UINT(_kern, OID_AUTO, kobj_methodcount, CTLFLAG_RD, 63118921Scg &kobj_next_id, 0, ""); 64118921Scg 6559093Sdfrstatic int 6659093Sdfrkobj_error_method(void) 6759093Sdfr{ 6859093Sdfr return ENXIO; 6959093Sdfr} 7059093Sdfr 7159093Sdfrstatic void 7259093Sdfrkobj_register_method(struct kobjop_desc *desc) 7359093Sdfr{ 74118921Scg if (desc->id == 0) { 75118921Scg KASSERT((kobj_next_id < KOBJ_CACHE_SIZE), ("kobj method table overflow")); 7659093Sdfr desc->id = kobj_next_id++; 77118921Scg } 7859093Sdfr} 7959093Sdfr 8059093Sdfrstatic void 8159093Sdfrkobj_unregister_method(struct kobjop_desc *desc) 8259093Sdfr{ 8359093Sdfr} 8459093Sdfr 8565173Sdfrstatic void 8665173Sdfrkobj_class_compile_common(kobj_class_t cls, kobj_ops_t ops) 8759093Sdfr{ 8859093Sdfr kobj_method_t *m; 8959093Sdfr int i; 9059093Sdfr 9159093Sdfr /* 9259093Sdfr * Don't do anything if we are already compiled. 9359093Sdfr */ 9459093Sdfr if (cls->ops) 9559093Sdfr return; 9659093Sdfr 9759093Sdfr /* 9859093Sdfr * First register any methods which need it. 9959093Sdfr */ 10059093Sdfr for (i = 0, m = cls->methods; m->desc; i++, m++) 10159093Sdfr kobj_register_method(m->desc); 10259093Sdfr 10359093Sdfr /* 10465173Sdfr * Then initialise the ops table. 10559093Sdfr */ 10659093Sdfr bzero(ops, sizeof(struct kobj_ops)); 10759093Sdfr ops->cls = cls; 10859093Sdfr cls->ops = ops; 10959093Sdfr} 11059093Sdfr 11159093Sdfrvoid 11265173Sdfrkobj_class_compile(kobj_class_t cls) 11365173Sdfr{ 11465173Sdfr kobj_ops_t ops; 11565173Sdfr 11665173Sdfr /* 11765173Sdfr * Allocate space for the compiled ops table. 11865173Sdfr */ 11965173Sdfr ops = malloc(sizeof(struct kobj_ops), M_KOBJ, M_NOWAIT); 12065173Sdfr if (!ops) 12165173Sdfr panic("kobj_compile_methods: out of memory"); 12265173Sdfr kobj_class_compile_common(cls, ops); 12365173Sdfr} 12465173Sdfr 12565173Sdfrvoid 12665173Sdfrkobj_class_compile_static(kobj_class_t cls, kobj_ops_t ops) 12765173Sdfr{ 12865173Sdfr /* 12965173Sdfr * Increment refs to make sure that the ops table is not freed. 13065173Sdfr */ 13165173Sdfr cls->refs++; 13265173Sdfr kobj_class_compile_common(cls, ops); 13365173Sdfr} 13465173Sdfr 13565173Sdfrvoid 13659093Sdfrkobj_lookup_method(kobj_method_t *methods, 13759093Sdfr kobj_method_t *ce, 13859093Sdfr kobjop_desc_t desc) 13959093Sdfr{ 14059093Sdfr ce->desc = desc; 14159093Sdfr for (; methods && methods->desc; methods++) { 14259093Sdfr if (methods->desc == desc) { 14359093Sdfr ce->func = methods->func; 14459093Sdfr return; 14559093Sdfr } 14659093Sdfr } 14759093Sdfr if (desc->deflt) 14859093Sdfr ce->func = desc->deflt; 14959093Sdfr else 15059093Sdfr ce->func = kobj_error_method; 15159093Sdfr return; 15259093Sdfr} 15359093Sdfr 15459093Sdfrvoid 15559093Sdfrkobj_class_free(kobj_class_t cls) 15659093Sdfr{ 15759093Sdfr int i; 15859093Sdfr kobj_method_t *m; 15959093Sdfr 16059093Sdfr /* 16159093Sdfr * Unregister any methods which are no longer used. 16259093Sdfr */ 16359093Sdfr for (i = 0, m = cls->methods; m->desc; i++, m++) 16459093Sdfr kobj_unregister_method(m->desc); 16559093Sdfr 16659093Sdfr /* 16759093Sdfr * Free memory and clean up. 16859093Sdfr */ 16959093Sdfr free(cls->ops, M_KOBJ); 17059093Sdfr cls->ops = 0; 17159093Sdfr} 17259093Sdfr 17359093Sdfrkobj_t 17459093Sdfrkobj_create(kobj_class_t cls, 17559093Sdfr struct malloc_type *mtype, 17659093Sdfr int mflags) 17759093Sdfr{ 17859093Sdfr kobj_t obj; 17959093Sdfr 18059093Sdfr /* 18159093Sdfr * Allocate and initialise the new object. 18259093Sdfr */ 18369781Sdwmalone obj = malloc(cls->size, mtype, mflags | M_ZERO); 18459093Sdfr if (!obj) 18559093Sdfr return 0; 18659093Sdfr kobj_init(obj, cls); 18759093Sdfr 18859093Sdfr return obj; 18959093Sdfr} 19059093Sdfr 19159093Sdfrvoid 19259093Sdfrkobj_init(kobj_t obj, kobj_class_t cls) 19359093Sdfr{ 19459093Sdfr /* 19559093Sdfr * Consider compiling the class' method table. 19659093Sdfr */ 19759093Sdfr if (!cls->ops) 19859093Sdfr kobj_class_compile(cls); 19959093Sdfr 20059093Sdfr obj->ops = cls->ops; 20159820Sdfr cls->refs++; 20259093Sdfr} 20359093Sdfr 20459093Sdfrvoid 20559093Sdfrkobj_delete(kobj_t obj, struct malloc_type *mtype) 20659093Sdfr{ 20759093Sdfr kobj_class_t cls = obj->ops->cls; 20859093Sdfr 20959093Sdfr /* 21059093Sdfr * Consider freeing the compiled method table for the class 21159093Sdfr * after its last instance is deleted. As an optimisation, we 21259093Sdfr * should defer this for a short while to avoid thrashing. 21359093Sdfr */ 21459820Sdfr cls->refs--; 21559820Sdfr if (!cls->refs) 21659093Sdfr kobj_class_free(cls); 21759093Sdfr 21859093Sdfr obj->ops = 0; 21959093Sdfr if (mtype) 22059093Sdfr free(obj, mtype); 22159093Sdfr} 222