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