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