File:  [DragonFly] / src / sys / kern / subr_kobj.c
Revision 1.6: download - view: text, annotated - select for diffs
Thu Apr 1 13:50:47 2004 UTC (10 years, 6 months ago) by joerg
Branches: MAIN
CVS tags: HEAD
KObj extension stage II/III

Tokenize kobj to make it SMP safe. This is based on the assumption that
drivers are responsible for not removing active devices. This allows us
to avoid all locks / critical sections for method lookup and object
instantiation / uninstanziation, leaving only the class management.

    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.6 2004/04/01 13:50:47 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: static int
   75: kobj_error_method(void)
   76: {
   77: 	return ENXIO;
   78: }
   79: 
   80: static void
   81: kobj_register_method(struct kobjop_desc *desc)
   82: {
   83: 	if (desc->id == 0)
   84: 		desc->id = kobj_next_id++;
   85: }
   86: 
   87: static void
   88: kobj_unregister_method(struct kobjop_desc *desc)
   89: {
   90: }
   91: 
   92: static void
   93: kobj_class_compile(kobj_class_t cls)
   94: {
   95: 	kobj_method_t *m;
   96: 	kobj_ops_t ops;
   97: 
   98: 	/*
   99: 	 * Don't do anything if we are already compiled.
  100: 	 */
  101: 	if (cls->ops)
  102: 		return;
  103: 
  104: 	/*
  105: 	 * Allocate space for the compiled ops table.
  106: 	 */
  107: 	ops = malloc(sizeof(struct kobj_ops), M_KOBJ, M_INTWAIT | M_ZERO);
  108: 	if (cls->ops) {
  109: 		/*
  110: 		 * In case of preemption, another thread might have been faster,
  111: 		 * but that's fine for us.
  112: 		 */
  113: 		if (ops)
  114: 			free(ops, M_KOBJ);
  115: 		return;
  116: 	}	
  117: 
  118: 	if (!ops)
  119: 		panic("kobj_compile_methods: out of memory");
  120: 
  121: 	ops->cls = cls;
  122: 	cls->ops = ops;
  123: 
  124: 	/*
  125: 	 * Afterwards register any methods which need it.
  126: 	 */
  127: 	for (m = cls->methods; m->desc; m++)
  128: 		kobj_register_method(m->desc);
  129: }
  130: 
  131: void
  132: kobj_lookup_method(kobj_method_t *methods,
  133: 		   kobj_method_t *ce,
  134: 		   kobjop_desc_t desc)
  135: {
  136: 	ce->desc = desc;
  137: 	for (; methods && methods->desc; methods++) {
  138: 		if (methods->desc == desc) {
  139: 			ce->func = methods->func;
  140: 			return;
  141: 		}
  142: 	}
  143: 	if (desc->deflt)
  144: 		ce->func = desc->deflt;
  145: 	else
  146: 		ce->func = kobj_error_method;
  147: 	return;
  148: }
  149: 
  150: static void
  151: kobj_class_free(kobj_class_t cls)
  152: {
  153: 	int i;
  154: 	kobj_method_t *m;
  155: 
  156: 	/*
  157: 	 * Unregister any methods which are no longer used.
  158: 	 */
  159: 	for (i = 0, m = cls->methods; m->desc; i++, m++)
  160: 		kobj_unregister_method(m->desc);
  161: 
  162: 	/*
  163: 	 * Free memory and clean up.
  164: 	 */
  165: 	free(cls->ops, M_KOBJ);
  166: 	cls->ops = 0;
  167: }
  168: 
  169: void
  170: kobj_class_instantiate(kobj_class_t cls)
  171: {
  172: 	lwkt_tokref ilock;
  173: 
  174: 	lwkt_gettoken(&ilock, &kobj_token);
  175: 	crit_enter();
  176: 
  177: 	if (!cls->ops)
  178: 		kobj_class_compile(cls);
  179: 	cls->refs++;
  180: 
  181: 	crit_exit();
  182: 	lwkt_reltoken(&ilock);
  183: }
  184: 
  185: void
  186: kobj_class_uninstantiate(kobj_class_t cls)
  187: {
  188: 	lwkt_tokref ilock;
  189: 
  190: 	lwkt_gettoken(&ilock, &kobj_token);
  191: 	crit_enter();
  192: 
  193: 	cls->refs--;
  194: 	if (cls->refs == 0)
  195: 		kobj_class_free(cls);
  196: 
  197: 	crit_exit();
  198: 	lwkt_reltoken(&ilock);
  199: }
  200: 
  201: kobj_t
  202: kobj_create(kobj_class_t cls,
  203: 	    struct malloc_type *mtype,
  204: 	    int mflags)
  205: {
  206: 	kobj_t obj;
  207: 
  208: 	/*
  209: 	 * Allocate and initialise the new object.
  210: 	 */
  211: 	obj = malloc(cls->size, mtype, mflags | M_ZERO);
  212: 	if (!obj)
  213: 		return 0;
  214: 	kobj_init(obj, cls);
  215: 
  216: 	return obj;
  217: }
  218: 
  219: void
  220: kobj_init(kobj_t obj, kobj_class_t cls)
  221: {
  222: 	kobj_class_instantiate(cls);
  223: 	obj->ops = cls->ops;
  224: }
  225: 
  226: void
  227: kobj_delete(kobj_t obj, struct malloc_type *mtype)
  228: {
  229: 	kobj_class_t cls = obj->ops->cls;
  230: 
  231: 	kobj_class_uninstantiate(cls);
  232: 
  233: 	obj->ops = 0;
  234: 	if (mtype)
  235: 		free(obj, mtype);
  236: }