xref: /f-stack/freebsd/sys/kobj.h (revision 22ce4aff)
1a9643ea8Slogwang /*-
2*22ce4affSfengbojiang  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*22ce4affSfengbojiang  *
4a9643ea8Slogwang  * Copyright (c) 2000,2003 Doug Rabson
5a9643ea8Slogwang  * All rights reserved.
6a9643ea8Slogwang  *
7a9643ea8Slogwang  * Redistribution and use in source and binary forms, with or without
8a9643ea8Slogwang  * modification, are permitted provided that the following conditions
9a9643ea8Slogwang  * are met:
10a9643ea8Slogwang  * 1. Redistributions of source code must retain the above copyright
11a9643ea8Slogwang  *    notice, this list of conditions and the following disclaimer.
12a9643ea8Slogwang  * 2. Redistributions in binary form must reproduce the above copyright
13a9643ea8Slogwang  *    notice, this list of conditions and the following disclaimer in the
14a9643ea8Slogwang  *    documentation and/or other materials provided with the distribution.
15a9643ea8Slogwang  *
16a9643ea8Slogwang  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17a9643ea8Slogwang  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18a9643ea8Slogwang  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19a9643ea8Slogwang  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20a9643ea8Slogwang  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21a9643ea8Slogwang  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22a9643ea8Slogwang  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23a9643ea8Slogwang  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24a9643ea8Slogwang  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25a9643ea8Slogwang  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26a9643ea8Slogwang  * SUCH DAMAGE.
27a9643ea8Slogwang  *
28a9643ea8Slogwang  *	$FreeBSD$
29a9643ea8Slogwang  */
30a9643ea8Slogwang 
31a9643ea8Slogwang #ifndef _SYS_KOBJ_H_
32a9643ea8Slogwang #define _SYS_KOBJ_H_
33a9643ea8Slogwang 
34a9643ea8Slogwang /*
35a9643ea8Slogwang  * Forward declarations
36a9643ea8Slogwang  */
37a9643ea8Slogwang typedef struct kobj		*kobj_t;
38a9643ea8Slogwang typedef struct kobj_class	*kobj_class_t;
39a9643ea8Slogwang typedef const struct kobj_method kobj_method_t;
40a9643ea8Slogwang typedef int			(*kobjop_t)(void);
41a9643ea8Slogwang typedef struct kobj_ops		*kobj_ops_t;
42a9643ea8Slogwang typedef struct kobjop_desc	*kobjop_desc_t;
43a9643ea8Slogwang struct malloc_type;
44a9643ea8Slogwang 
45a9643ea8Slogwang struct kobj_method {
46a9643ea8Slogwang 	kobjop_desc_t	desc;
47a9643ea8Slogwang 	kobjop_t	func;
48a9643ea8Slogwang };
49a9643ea8Slogwang 
50a9643ea8Slogwang /*
51a9643ea8Slogwang  * A class is simply a method table and a sizeof value. When the first
52a9643ea8Slogwang  * instance of the class is created, the method table will be compiled
53a9643ea8Slogwang  * into a form more suited to efficient method dispatch. This compiled
54a9643ea8Slogwang  * method table is always the first field of the object.
55a9643ea8Slogwang  */
56a9643ea8Slogwang #define KOBJ_CLASS_FIELDS						\
57a9643ea8Slogwang 	const char	*name;		/* class name */		\
58a9643ea8Slogwang 	kobj_method_t	*methods;	/* method table */		\
59a9643ea8Slogwang 	size_t		size;		/* object size */		\
60a9643ea8Slogwang 	kobj_class_t	*baseclasses;	/* base classes */		\
61a9643ea8Slogwang 	u_int		refs;		/* reference count */		\
62a9643ea8Slogwang 	kobj_ops_t	ops		/* compiled method table */
63a9643ea8Slogwang 
64a9643ea8Slogwang struct kobj_class {
65a9643ea8Slogwang 	KOBJ_CLASS_FIELDS;
66a9643ea8Slogwang };
67a9643ea8Slogwang 
68a9643ea8Slogwang /*
69a9643ea8Slogwang  * Implementation of kobj.
70a9643ea8Slogwang  */
71a9643ea8Slogwang #define KOBJ_FIELDS				\
72a9643ea8Slogwang 	kobj_ops_t	ops
73a9643ea8Slogwang 
74a9643ea8Slogwang struct kobj {
75a9643ea8Slogwang 	KOBJ_FIELDS;
76a9643ea8Slogwang };
77a9643ea8Slogwang 
78a9643ea8Slogwang /*
79a9643ea8Slogwang  * The ops table is used as a cache of results from kobj_lookup_method().
80a9643ea8Slogwang  */
81a9643ea8Slogwang 
82a9643ea8Slogwang #define KOBJ_CACHE_SIZE	256
83a9643ea8Slogwang 
84a9643ea8Slogwang struct kobj_ops {
85a9643ea8Slogwang 	kobj_method_t	*cache[KOBJ_CACHE_SIZE];
86a9643ea8Slogwang 	kobj_class_t	cls;
87a9643ea8Slogwang };
88a9643ea8Slogwang 
89a9643ea8Slogwang struct kobjop_desc {
90a9643ea8Slogwang 	unsigned int	id;		/* unique ID */
91a9643ea8Slogwang 	kobj_method_t	deflt;		/* default implementation */
92a9643ea8Slogwang };
93a9643ea8Slogwang 
94a9643ea8Slogwang /*
95a9643ea8Slogwang  * Shorthand for constructing method tables.
96a9643ea8Slogwang  * The ternary operator is (ab)used to provoke a warning when FUNC
97a9643ea8Slogwang  * has a signature that is not compatible with kobj method signature.
98a9643ea8Slogwang  */
99a9643ea8Slogwang #define KOBJMETHOD(NAME, FUNC) \
100a9643ea8Slogwang 	{ &NAME##_desc, (kobjop_t) (1 ? FUNC : (NAME##_t *)NULL) }
101a9643ea8Slogwang 
102a9643ea8Slogwang /*
103a9643ea8Slogwang  *
104a9643ea8Slogwang  */
105a9643ea8Slogwang #define KOBJMETHOD_END	{ NULL, NULL }
106a9643ea8Slogwang 
107a9643ea8Slogwang /*
108a9643ea8Slogwang  * Declare a class (which should be defined in another file.
109a9643ea8Slogwang  */
110a9643ea8Slogwang #define DECLARE_CLASS(name) extern struct kobj_class name
111a9643ea8Slogwang 
112a9643ea8Slogwang /*
113a9643ea8Slogwang  * Define a class with no base classes (api backward-compatible. with
114a9643ea8Slogwang  * FreeBSD-5.1 and earlier).
115a9643ea8Slogwang  */
116a9643ea8Slogwang #define DEFINE_CLASS(name, methods, size)     		\
117a9643ea8Slogwang DEFINE_CLASS_0(name, name ## _class, methods, size)
118a9643ea8Slogwang 
119a9643ea8Slogwang /*
120a9643ea8Slogwang  * Define a class with no base classes. Use like this:
121a9643ea8Slogwang  *
122a9643ea8Slogwang  * DEFINE_CLASS_0(foo, foo_class, foo_methods, sizeof(foo_softc));
123a9643ea8Slogwang  */
124a9643ea8Slogwang #define DEFINE_CLASS_0(name, classvar, methods, size)	\
125a9643ea8Slogwang 							\
126a9643ea8Slogwang struct kobj_class classvar = {				\
127a9643ea8Slogwang 	#name, methods, size, NULL			\
128a9643ea8Slogwang }
129a9643ea8Slogwang 
130a9643ea8Slogwang /*
131a9643ea8Slogwang  * Define a class inheriting a single base class. Use like this:
132a9643ea8Slogwang  *
133a9643ea8Slogwang  * DEFINE_CLASS_1(foo, foo_class, foo_methods, sizeof(foo_softc),
134a9643ea8Slogwang  *			  bar);
135a9643ea8Slogwang  */
136a9643ea8Slogwang #define DEFINE_CLASS_1(name, classvar, methods, size,	\
137a9643ea8Slogwang 		       base1)				\
138a9643ea8Slogwang 							\
139a9643ea8Slogwang static kobj_class_t name ## _baseclasses[] =		\
140a9643ea8Slogwang 	{ &base1, NULL };				\
141a9643ea8Slogwang struct kobj_class classvar = {				\
142a9643ea8Slogwang 	#name, methods, size, name ## _baseclasses	\
143a9643ea8Slogwang }
144a9643ea8Slogwang 
145a9643ea8Slogwang /*
146a9643ea8Slogwang  * Define a class inheriting two base classes. Use like this:
147a9643ea8Slogwang  *
148a9643ea8Slogwang  * DEFINE_CLASS_2(foo, foo_class, foo_methods, sizeof(foo_softc),
149a9643ea8Slogwang  *			  bar, baz);
150a9643ea8Slogwang  */
151a9643ea8Slogwang #define DEFINE_CLASS_2(name, classvar, methods, size,	\
152a9643ea8Slogwang 	               base1, base2)			\
153a9643ea8Slogwang 							\
154a9643ea8Slogwang static kobj_class_t name ## _baseclasses[] =		\
155a9643ea8Slogwang 	{ &base1,					\
156a9643ea8Slogwang 	  &base2, NULL };				\
157a9643ea8Slogwang struct kobj_class classvar = {				\
158a9643ea8Slogwang 	#name, methods, size, name ## _baseclasses	\
159a9643ea8Slogwang }
160a9643ea8Slogwang 
161a9643ea8Slogwang /*
162a9643ea8Slogwang  * Define a class inheriting three base classes. Use like this:
163a9643ea8Slogwang  *
164a9643ea8Slogwang  * DEFINE_CLASS_3(foo, foo_class, foo_methods, sizeof(foo_softc),
165a9643ea8Slogwang  *			  bar, baz, foobar);
166a9643ea8Slogwang  */
167a9643ea8Slogwang #define DEFINE_CLASS_3(name, classvar, methods, size,	\
168a9643ea8Slogwang 		       base1, base2, base3)		\
169a9643ea8Slogwang 							\
170a9643ea8Slogwang static kobj_class_t name ## _baseclasses[] =		\
171a9643ea8Slogwang 	{ &base1,					\
172a9643ea8Slogwang 	  &base2,					\
173a9643ea8Slogwang 	  &base3, NULL };				\
174a9643ea8Slogwang struct kobj_class classvar = {				\
175a9643ea8Slogwang 	#name, methods, size, name ## _baseclasses	\
176a9643ea8Slogwang }
177a9643ea8Slogwang 
178a9643ea8Slogwang /*
179a9643ea8Slogwang  * Compile the method table in a class.
180a9643ea8Slogwang  */
181a9643ea8Slogwang void		kobj_class_compile(kobj_class_t cls);
182a9643ea8Slogwang 
183a9643ea8Slogwang /*
184a9643ea8Slogwang  * Compile the method table, with the caller providing the space for
185a9643ea8Slogwang  * the ops table.(for use before malloc is initialised).
186a9643ea8Slogwang  */
187a9643ea8Slogwang void		kobj_class_compile_static(kobj_class_t cls, kobj_ops_t ops);
188a9643ea8Slogwang 
189a9643ea8Slogwang /*
190a9643ea8Slogwang  * Free the compiled method table in a class.
191a9643ea8Slogwang  */
192a9643ea8Slogwang void		kobj_class_free(kobj_class_t cls);
193a9643ea8Slogwang 
194a9643ea8Slogwang /*
195a9643ea8Slogwang  * Allocate memory for and initialise a new object.
196a9643ea8Slogwang  */
197a9643ea8Slogwang kobj_t		kobj_create(kobj_class_t cls,
198a9643ea8Slogwang 			    struct malloc_type *mtype,
199a9643ea8Slogwang 			    int mflags);
200a9643ea8Slogwang 
201a9643ea8Slogwang /*
202a9643ea8Slogwang  * Initialise a pre-allocated object.
203a9643ea8Slogwang  */
204a9643ea8Slogwang void		kobj_init(kobj_t obj, kobj_class_t cls);
205a9643ea8Slogwang void		kobj_init_static(kobj_t obj, kobj_class_t cls);
206a9643ea8Slogwang 
207a9643ea8Slogwang /*
208a9643ea8Slogwang  * Delete an object. If mtype is non-zero, free the memory.
209a9643ea8Slogwang  */
210a9643ea8Slogwang void		kobj_delete(kobj_t obj, struct malloc_type *mtype);
211a9643ea8Slogwang 
212a9643ea8Slogwang /*
213a9643ea8Slogwang  * Maintain stats on hits/misses in lookup caches.
214a9643ea8Slogwang  */
215a9643ea8Slogwang #ifdef KOBJ_STATS
216a9643ea8Slogwang extern u_int kobj_lookup_hits;
217a9643ea8Slogwang extern u_int kobj_lookup_misses;
218a9643ea8Slogwang #endif
219a9643ea8Slogwang 
220a9643ea8Slogwang /*
221a9643ea8Slogwang  * Lookup the method in the cache and if it isn't there look it up the
222a9643ea8Slogwang  * slow way.
223a9643ea8Slogwang  */
224a9643ea8Slogwang #ifdef KOBJ_STATS
225a9643ea8Slogwang #define KOBJOPLOOKUP(OPS,OP) do {				\
226a9643ea8Slogwang 	kobjop_desc_t _desc = &OP##_##desc;			\
227a9643ea8Slogwang 	kobj_method_t **_cep =					\
228a9643ea8Slogwang 	    &OPS->cache[_desc->id & (KOBJ_CACHE_SIZE-1)];	\
229a9643ea8Slogwang 	kobj_method_t *_ce = *_cep;				\
230*22ce4affSfengbojiang 	if (_ce->desc != _desc) {				\
231a9643ea8Slogwang 		_ce = kobj_lookup_method(OPS->cls,		\
232a9643ea8Slogwang 					 _cep, _desc);		\
233*22ce4affSfengbojiang 		kobj_lookup_misses++;				\
234*22ce4affSfengbojiang 	} else							\
235*22ce4affSfengbojiang 		kobj_lookup_hits++;				\
236a9643ea8Slogwang 	_m = _ce->func;						\
237a9643ea8Slogwang } while(0)
238a9643ea8Slogwang #else
239a9643ea8Slogwang #define KOBJOPLOOKUP(OPS,OP) do {				\
240a9643ea8Slogwang 	kobjop_desc_t _desc = &OP##_##desc;			\
241a9643ea8Slogwang 	kobj_method_t **_cep =					\
242a9643ea8Slogwang 	    &OPS->cache[_desc->id & (KOBJ_CACHE_SIZE-1)];	\
243a9643ea8Slogwang 	kobj_method_t *_ce = *_cep;				\
244a9643ea8Slogwang 	if (_ce->desc != _desc)					\
245a9643ea8Slogwang 		_ce = kobj_lookup_method(OPS->cls,		\
246a9643ea8Slogwang 					 _cep, _desc);		\
247a9643ea8Slogwang 	_m = _ce->func;						\
248a9643ea8Slogwang } while(0)
249a9643ea8Slogwang #endif
250a9643ea8Slogwang 
251a9643ea8Slogwang kobj_method_t* kobj_lookup_method(kobj_class_t cls,
252a9643ea8Slogwang 				  kobj_method_t **cep,
253a9643ea8Slogwang 				  kobjop_desc_t desc);
254a9643ea8Slogwang 
255a9643ea8Slogwang /*
256a9643ea8Slogwang  * Default method implementation. Returns ENXIO.
257a9643ea8Slogwang  */
258a9643ea8Slogwang int kobj_error_method(void);
259a9643ea8Slogwang 
260a9643ea8Slogwang #endif /* !_SYS_KOBJ_H_ */
261