1 | /*- |
---|
2 | * Copyright (c) 2000,2003 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$ |
---|
27 | */ |
---|
28 | |
---|
29 | #ifndef _SYS_KOBJ_H_ |
---|
30 | #define _SYS_KOBJ_H_ |
---|
31 | |
---|
32 | /* |
---|
33 | * Forward declarations |
---|
34 | */ |
---|
35 | typedef struct kobj *kobj_t; |
---|
36 | typedef struct kobj_class *kobj_class_t; |
---|
37 | typedef struct kobj_method kobj_method_t; |
---|
38 | typedef int (*kobjop_t)(void); |
---|
39 | typedef struct kobj_ops *kobj_ops_t; |
---|
40 | typedef struct kobjop_desc *kobjop_desc_t; |
---|
41 | struct malloc_type; |
---|
42 | |
---|
43 | struct kobj_method { |
---|
44 | kobjop_desc_t desc; |
---|
45 | kobjop_t func; |
---|
46 | }; |
---|
47 | |
---|
48 | /* |
---|
49 | * A class is simply a method table and a sizeof value. When the first |
---|
50 | * instance of the class is created, the method table will be compiled |
---|
51 | * into a form more suited to efficient method dispatch. This compiled |
---|
52 | * method table is always the first field of the object. |
---|
53 | */ |
---|
54 | #define KOBJ_CLASS_FIELDS \ |
---|
55 | const char *name; /* class name */ \ |
---|
56 | kobj_method_t *methods; /* method table */ \ |
---|
57 | size_t size; /* object size */ \ |
---|
58 | kobj_class_t *baseclasses; /* base classes */ \ |
---|
59 | u_int refs; /* reference count */ \ |
---|
60 | kobj_ops_t ops /* compiled method table */ |
---|
61 | |
---|
62 | struct kobj_class { |
---|
63 | KOBJ_CLASS_FIELDS; |
---|
64 | }; |
---|
65 | |
---|
66 | /* |
---|
67 | * Implementation of kobj. |
---|
68 | */ |
---|
69 | #define KOBJ_FIELDS \ |
---|
70 | kobj_ops_t ops |
---|
71 | |
---|
72 | struct kobj { |
---|
73 | KOBJ_FIELDS; |
---|
74 | }; |
---|
75 | |
---|
76 | /* |
---|
77 | * The ops table is used as a cache of results from kobj_lookup_method(). |
---|
78 | */ |
---|
79 | |
---|
80 | #define KOBJ_CACHE_SIZE 256 |
---|
81 | |
---|
82 | struct kobj_ops { |
---|
83 | kobj_method_t *cache[KOBJ_CACHE_SIZE]; |
---|
84 | kobj_class_t cls; |
---|
85 | }; |
---|
86 | |
---|
87 | struct kobjop_desc { |
---|
88 | unsigned int id; /* unique ID */ |
---|
89 | kobj_method_t *deflt; /* default implementation */ |
---|
90 | }; |
---|
91 | |
---|
92 | /* |
---|
93 | * Shorthand for constructing method tables. |
---|
94 | * The ternary operator is (ab)used to provoke a warning when FUNC |
---|
95 | * has a signature that is not compatible with kobj method signature. |
---|
96 | */ |
---|
97 | #define KOBJMETHOD(NAME, FUNC) \ |
---|
98 | { &NAME##_desc, (kobjop_t) (1 ? FUNC : (NAME##_t *)NULL) } |
---|
99 | |
---|
100 | /* |
---|
101 | * |
---|
102 | */ |
---|
103 | #define KOBJMETHOD_END { NULL, NULL } |
---|
104 | |
---|
105 | /* |
---|
106 | * Declare a class (which should be defined in another file. |
---|
107 | */ |
---|
108 | #define DECLARE_CLASS(name) extern struct kobj_class name |
---|
109 | |
---|
110 | /* |
---|
111 | * Define a class with no base classes (api backward-compatible. with |
---|
112 | * FreeBSD-5.1 and earlier). |
---|
113 | */ |
---|
114 | #define DEFINE_CLASS(name, methods, size) \ |
---|
115 | DEFINE_CLASS_0(name, name ## _class, methods, size) |
---|
116 | |
---|
117 | /* |
---|
118 | * Define a class with no base classes. Use like this: |
---|
119 | * |
---|
120 | * DEFINE_CLASS_0(foo, foo_class, foo_methods, sizeof(foo_softc)); |
---|
121 | */ |
---|
122 | #define DEFINE_CLASS_0(name, classvar, methods, size) \ |
---|
123 | \ |
---|
124 | struct kobj_class classvar = { \ |
---|
125 | #name, methods, size, NULL \ |
---|
126 | } |
---|
127 | |
---|
128 | /* |
---|
129 | * Define a class inheriting a single base class. Use like this: |
---|
130 | * |
---|
131 | * DEFINE_CLASS_1(foo, foo_class, foo_methods, sizeof(foo_softc), |
---|
132 | * bar); |
---|
133 | */ |
---|
134 | #define DEFINE_CLASS_1(name, classvar, methods, size, \ |
---|
135 | base1) \ |
---|
136 | \ |
---|
137 | static kobj_class_t name ## _baseclasses[] = \ |
---|
138 | { &base1, NULL }; \ |
---|
139 | struct kobj_class classvar = { \ |
---|
140 | #name, methods, size, name ## _baseclasses \ |
---|
141 | } |
---|
142 | |
---|
143 | /* |
---|
144 | * Define a class inheriting two base classes. Use like this: |
---|
145 | * |
---|
146 | * DEFINE_CLASS_2(foo, foo_class, foo_methods, sizeof(foo_softc), |
---|
147 | * bar, baz); |
---|
148 | */ |
---|
149 | #define DEFINE_CLASS_2(name, methods, size, \ |
---|
150 | base1, base2) \ |
---|
151 | \ |
---|
152 | static kobj_class_t name ## _baseclasses[] = \ |
---|
153 | { &base1, \ |
---|
154 | &base2, NULL }; \ |
---|
155 | struct kobj_class name ## _class = { \ |
---|
156 | #name, methods, size, name ## _baseclasses \ |
---|
157 | } |
---|
158 | |
---|
159 | /* |
---|
160 | * Define a class inheriting three base classes. Use like this: |
---|
161 | * |
---|
162 | * DEFINE_CLASS_3(foo, foo_class, foo_methods, sizeof(foo_softc), |
---|
163 | * bar, baz, foobar); |
---|
164 | */ |
---|
165 | #define DEFINE_CLASS_3(name, methods, size, \ |
---|
166 | base1, base2, base3) \ |
---|
167 | \ |
---|
168 | static kobj_class_t name ## _baseclasses[] = \ |
---|
169 | { &base1, \ |
---|
170 | &base2, \ |
---|
171 | &base3, NULL }; \ |
---|
172 | struct kobj_class name ## _class = { \ |
---|
173 | #name, methods, size, name ## _baseclasses \ |
---|
174 | } |
---|
175 | |
---|
176 | |
---|
177 | /* |
---|
178 | * Compile the method table in a class. |
---|
179 | */ |
---|
180 | void kobj_class_compile(kobj_class_t cls); |
---|
181 | |
---|
182 | /* |
---|
183 | * Compile the method table, with the caller providing the space for |
---|
184 | * the ops table.(for use before malloc is initialised). |
---|
185 | */ |
---|
186 | void kobj_class_compile_static(kobj_class_t cls, kobj_ops_t ops); |
---|
187 | |
---|
188 | /* |
---|
189 | * Free the compiled method table in a class. |
---|
190 | */ |
---|
191 | void kobj_class_free(kobj_class_t cls); |
---|
192 | |
---|
193 | /* |
---|
194 | * Allocate memory for and initialise a new object. |
---|
195 | */ |
---|
196 | kobj_t kobj_create(kobj_class_t cls, |
---|
197 | struct malloc_type *mtype, |
---|
198 | int mflags); |
---|
199 | |
---|
200 | /* |
---|
201 | * Initialise a pre-allocated object. |
---|
202 | */ |
---|
203 | void kobj_init(kobj_t obj, kobj_class_t cls); |
---|
204 | void kobj_init_static(kobj_t obj, kobj_class_t cls); |
---|
205 | |
---|
206 | /* |
---|
207 | * Delete an object. If mtype is non-zero, free the memory. |
---|
208 | */ |
---|
209 | void kobj_delete(kobj_t obj, struct malloc_type *mtype); |
---|
210 | |
---|
211 | /* |
---|
212 | * Maintain stats on hits/misses in lookup caches. |
---|
213 | */ |
---|
214 | #ifdef KOBJ_STATS |
---|
215 | extern u_int kobj_lookup_hits; |
---|
216 | extern u_int kobj_lookup_misses; |
---|
217 | #endif |
---|
218 | |
---|
219 | /* |
---|
220 | * Lookup the method in the cache and if it isn't there look it up the |
---|
221 | * slow way. |
---|
222 | */ |
---|
223 | #ifdef KOBJ_STATS |
---|
224 | #define KOBJOPLOOKUP(OPS,OP) do { \ |
---|
225 | kobjop_desc_t _desc = &OP##_##desc; \ |
---|
226 | kobj_method_t **_cep = \ |
---|
227 | &OPS->cache[_desc->id & (KOBJ_CACHE_SIZE-1)]; \ |
---|
228 | kobj_method_t *_ce = *_cep; \ |
---|
229 | kobj_lookup_hits++; /* assume hit */ \ |
---|
230 | if (_ce->desc != _desc) \ |
---|
231 | _ce = kobj_lookup_method(OPS->cls, \ |
---|
232 | _cep, _desc); \ |
---|
233 | _m = _ce->func; \ |
---|
234 | } while(0) |
---|
235 | #else |
---|
236 | #define KOBJOPLOOKUP(OPS,OP) do { \ |
---|
237 | kobjop_desc_t _desc = &OP##_##desc; \ |
---|
238 | kobj_method_t **_cep = \ |
---|
239 | &OPS->cache[_desc->id & (KOBJ_CACHE_SIZE-1)]; \ |
---|
240 | kobj_method_t *_ce = *_cep; \ |
---|
241 | if (_ce->desc != _desc) \ |
---|
242 | _ce = kobj_lookup_method(OPS->cls, \ |
---|
243 | _cep, _desc); \ |
---|
244 | _m = _ce->func; \ |
---|
245 | } while(0) |
---|
246 | #endif |
---|
247 | |
---|
248 | kobj_method_t* kobj_lookup_method(kobj_class_t cls, |
---|
249 | kobj_method_t **cep, |
---|
250 | kobjop_desc_t desc); |
---|
251 | |
---|
252 | |
---|
253 | /* |
---|
254 | * Default method implementation. Returns ENXIO. |
---|
255 | */ |
---|
256 | int kobj_error_method(void); |
---|
257 | |
---|
258 | #endif /* !_SYS_KOBJ_H_ */ |
---|