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 (9 years, 2 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: }