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