File:  [DragonFly] / src / sys / kern / subr_kobj.c
Revision 1.7: download - view: text, annotated - select for diffs
Wed Apr 14 18:28:29 2004 UTC (10 years, 3 months ago) by joerg
Branches: MAIN
CVS tags: HEAD, DragonFly_Stable, DragonFly_Snap29Sep2004, DragonFly_Snap13Sep2004, DragonFly_RELEASE_1_6_Slip, DragonFly_RELEASE_1_6, DragonFly_RELEASE_1_4_Slip, DragonFly_RELEASE_1_4, DragonFly_RELEASE_1_2_Slip, DragonFly_RELEASE_1_2, DragonFly_1_0_REL, DragonFly_1_0_RC1, DragonFly_1_0A_REL
KObj extension stage IIIa/III

Merge inheritance support from FreeBSD:
  * Add multiple inheritance to kobj. Each class can have zero or more base
    classes and if a method is not found in a given class, its base classes
    are searched (in the order they were declared). This search is recursive,
    i.e. a method may be define in a base class of a base class.

    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.7 2004/04/14 18:28:29 joerg 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_SUB_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 = malloc(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: 			free(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: 	free(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 = malloc(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: 		free(obj, mtype);
  287: }