subr_kobj.c revision 116182
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
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sys/kern/subr_kobj.c 116182 2003-06-11 00:56:59Z obrien $");
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#ifndef TEST
37#include <sys/systm.h>
38#endif
39#include <sys/kobj.h>
40
41#ifdef TEST
42#include "usertest.h"
43#endif
44
45static MALLOC_DEFINE(M_KOBJ, "kobj", "Kernel object structures");
46
47#ifdef KOBJ_STATS
48
49#include <sys/sysctl.h>
50
51u_int kobj_lookup_hits;
52u_int kobj_lookup_misses;
53
54SYSCTL_UINT(_kern, OID_AUTO, kobj_hits, CTLFLAG_RD,
55	   &kobj_lookup_hits, 0, "")
56SYSCTL_UINT(_kern, OID_AUTO, kobj_misses, CTLFLAG_RD,
57	   &kobj_lookup_misses, 0, "")
58
59#endif
60
61static int kobj_next_id = 1;
62
63static int
64kobj_error_method(void)
65{
66	return ENXIO;
67}
68
69static void
70kobj_register_method(struct kobjop_desc *desc)
71{
72	if (desc->id == 0)
73		desc->id = kobj_next_id++;
74}
75
76static void
77kobj_unregister_method(struct kobjop_desc *desc)
78{
79}
80
81static void
82kobj_class_compile_common(kobj_class_t cls, kobj_ops_t ops)
83{
84	kobj_method_t *m;
85	int i;
86
87	/*
88	 * Don't do anything if we are already compiled.
89	 */
90	if (cls->ops)
91		return;
92
93	/*
94	 * First register any methods which need it.
95	 */
96	for (i = 0, m = cls->methods; m->desc; i++, m++)
97		kobj_register_method(m->desc);
98
99	/*
100	 * Then initialise the ops table.
101	 */
102	bzero(ops, sizeof(struct kobj_ops));
103	ops->cls = cls;
104	cls->ops = ops;
105}
106
107void
108kobj_class_compile(kobj_class_t cls)
109{
110	kobj_ops_t ops;
111
112	/*
113	 * Allocate space for the compiled ops table.
114	 */
115	ops = malloc(sizeof(struct kobj_ops), M_KOBJ, M_NOWAIT);
116	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