Fix a little redundancy from my last commit. The border cannot be outside
[dragonfly.git] / sys / sys / kobj.h
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.8 2004/12/30 07:01:52 cpressey 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, 0                         \
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_ */