subr_kobj.c revision 116182
11849Swollman/*-
21849Swollman * Copyright (c) 2000 Doug Rabson
31849Swollman * All rights reserved.
41849Swollman *
51849Swollman * Redistribution and use in source and binary forms, with or without
61849Swollman * modification, are permitted provided that the following conditions
71849Swollman * are met:
81849Swollman * 1. Redistributions of source code must retain the above copyright
91849Swollman *    notice, this list of conditions and the following disclaimer.
101849Swollman * 2. Redistributions in binary form must reproduce the above copyright
111849Swollman *    notice, this list of conditions and the following disclaimer in the
121849Swollman *    documentation and/or other materials provided with the distribution.
131849Swollman *
141849Swollman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
151849Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
161849Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171849Swollman * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
181849Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
191849Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
201849Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
211849Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
221849Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
231849Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
241849Swollman * SUCH DAMAGE.
251849Swollman */
261849Swollman
271849Swollman#include <sys/cdefs.h>
281849Swollman__FBSDID("$FreeBSD: head/sys/kern/subr_kobj.c 116182 2003-06-11 00:56:59Z obrien $");
291849Swollman
301849Swollman#include <sys/param.h>
311849Swollman#include <sys/queue.h>
321849Swollman#include <sys/malloc.h>
3392999Sobrien#include <sys/kernel.h>
3492999Sobrien#include <sys/module.h>
3592999Sobrien#include <sys/errno.h>
3692999Sobrien#ifndef TEST
3792999Sobrien#include <sys/systm.h>
381849Swollman#endif
391849Swollman#include <sys/kobj.h>
401849Swollman
411849Swollman#ifdef TEST
421849Swollman#include "usertest.h"
431849Swollman#endif
441849Swollman
451849Swollmanstatic MALLOC_DEFINE(M_KOBJ, "kobj", "Kernel object structures");
461849Swollman
471849Swollman#ifdef KOBJ_STATS
481849Swollman
491849Swollman#include <sys/sysctl.h>
501849Swollman
5156345Sjasoneu_int kobj_lookup_hits;
5252083Smarcelu_int kobj_lookup_misses;
5315634Speter
54229009SkibSYSCTL_UINT(_kern, OID_AUTO, kobj_hits, CTLFLAG_RD,
55229009Skib	   &kobj_lookup_hits, 0, "")
56229009SkibSYSCTL_UINT(_kern, OID_AUTO, kobj_misses, CTLFLAG_RD,
5751794Smarcel	   &kobj_lookup_misses, 0, "")
5851794Smarcel
5951794Smarcel#endif
6051794Smarcel
6171579Sdeischenstatic int kobj_next_id = 1;
62229009Skib
63229009Skibstatic int
64229009Skibkobj_error_method(void)
6551794Smarcel{
66229009Skib	return ENXIO;
6715634Speter}
6851794Smarcel
691849Swollmanstatic void
701849Swollmankobj_register_method(struct kobjop_desc *desc)
711849Swollman{
721849Swollman	if (desc->id == 0)
731849Swollman		desc->id = kobj_next_id++;
741849Swollman}
751849Swollman
7651794Smarcelstatic void
771849Swollmankobj_unregister_method(struct kobjop_desc *desc)
781849Swollman{
79184548Speter}
801849Swollman
8171579Sdeischenstatic void
8271579Sdeischenkobj_class_compile_common(kobj_class_t cls, kobj_ops_t ops)
8356345Sjasone{
841849Swollman	kobj_method_t *m;
8515634Speter	int i;
86229009Skib
87229009Skib	/*
88229009Skib	 * Don't do anything if we are already compiled.
8951794Smarcel	 */
9051794Smarcel	if (cls->ops)
9151794Smarcel		return;
9251794Smarcel
9371579Sdeischen	/*
94229009Skib	 * First register any methods which need it.
95229009Skib	 */
96229009Skib	for (i = 0, m = cls->methods; m->desc; i++, m++)
9751794Smarcel		kobj_register_method(m->desc);
98229009Skib
9915634Speter	/*
1001849Swollman	 * Then initialise the ops table.
1011849Swollman	 */
1021849Swollman	bzero(ops, sizeof(struct kobj_ops));
1031849Swollman	ops->cls = cls;
1041849Swollman	cls->ops = ops;
1051849Swollman}
1061849Swollman
1071849Swollmanvoid
10851794Smarcelkobj_class_compile(kobj_class_t cls)
1091849Swollman{
1101849Swollman	kobj_ops_t ops;
1111849Swollman
1121849Swollman	/*
1131849Swollman	 * Allocate space for the compiled ops table.
114184548Speter	 */
115217106Skib	ops = malloc(sizeof(struct kobj_ops), M_KOBJ, M_NOWAIT);
116217106Skib	if (!ops)
117		panic("kobj_compile_methods: out of memory");
118	kobj_class_compile_common(cls, ops);
119}
120
121void
122kobj_class_compile_static(kobj_class_t cls, kobj_ops_t ops)
123{
124	/*
125	 * Increment refs to make sure that the ops table is not freed.
126	 */
127	cls->refs++;
128	kobj_class_compile_common(cls, ops);
129}
130
131void
132kobj_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
150void
151kobj_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
169kobj_t
170kobj_create(kobj_class_t cls,
171	    struct malloc_type *mtype,
172	    int mflags)
173{
174	kobj_t obj;
175
176	/*
177	 * Allocate and initialise the new object.
178	 */
179	obj = malloc(cls->size, mtype, mflags | M_ZERO);
180	if (!obj)
181		return 0;
182	kobj_init(obj, cls);
183
184	return obj;
185}
186
187void
188kobj_init(kobj_t obj, kobj_class_t cls)
189{
190	/*
191	 * Consider compiling the class' method table.
192	 */
193	if (!cls->ops)
194		kobj_class_compile(cls);
195
196	obj->ops = cls->ops;
197	cls->refs++;
198}
199
200void
201kobj_delete(kobj_t obj, struct malloc_type *mtype)
202{
203	kobj_class_t cls = obj->ops->cls;
204
205	/*
206	 * Consider freeing the compiled method table for the class
207	 * after its last instance is deleted. As an optimisation, we
208	 * should defer this for a short while to avoid thrashing.
209	 */
210	cls->refs--;
211	if (!cls->refs)
212		kobj_class_free(cls);
213
214	obj->ops = 0;
215	if (mtype)
216		free(obj, mtype);
217}
218