summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/kern/subr_bus.c168
-rw-r--r--sys/kern/subr_kobj.c188
-rw-r--r--sys/sys/bus.h45
-rw-r--r--sys/sys/kobj.h136
-rw-r--r--sys/sys/param.h2
5 files changed, 376 insertions, 163 deletions
diff --git a/sys/kern/subr_bus.c b/sys/kern/subr_bus.c
index 03049bf..9a65242 100644
--- a/sys/kern/subr_bus.c
+++ b/sys/kern/subr_bus.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1997,1998 Doug Rabson
+ * Copyright (c) 1997,1998,2003 Doug Rabson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -62,8 +62,8 @@ SYSCTL_NODE(_hw, OID_AUTO, bus, CTLFLAG_RW, NULL, NULL);
*/
typedef struct driverlink *driverlink_t;
struct driverlink {
- driver_t *driver;
- TAILQ_ENTRY(driverlink) link; /* list of drivers in devclass */
+ kobj_class_t driver;
+ TAILQ_ENTRY(driverlink) link; /* list of drivers in devclass */
};
/*
@@ -75,6 +75,7 @@ typedef TAILQ_HEAD(device_list, device) device_list_t;
struct devclass {
TAILQ_ENTRY(devclass) link;
+ devclass_t parent; /* parent in devclass hierarchy */
driver_list_t drivers; /* bus devclasses store drivers for bus */
char *name;
device_t *devices; /* array of devices indexed by unit */
@@ -509,7 +510,8 @@ DEFINE_CLASS(null, null_methods, 0);
static devclass_list_t devclasses = TAILQ_HEAD_INITIALIZER(devclasses);
static devclass_t
-devclass_find_internal(const char *classname, int create)
+devclass_find_internal(const char *classname, const char *parentname,
+ int create)
{
devclass_t dc;
@@ -519,15 +521,16 @@ devclass_find_internal(const char *classname, int create)
TAILQ_FOREACH(dc, &devclasses, link) {
if (!strcmp(dc->name, classname))
- return (dc);
+ break;
}
- PDEBUG(("%s not found%s", classname, (create? ", creating": "")));
- if (create) {
+ if (create && !dc) {
+ PDEBUG(("creating %s", classname));
dc = malloc(sizeof(struct devclass) + strlen(classname) + 1,
M_BUS, M_NOWAIT|M_ZERO);
if (!dc)
return (NULL);
+ dc->parent = NULL;
dc->name = (char*) (dc + 1);
strcpy(dc->name, classname);
TAILQ_INIT(&dc->drivers);
@@ -535,6 +538,9 @@ devclass_find_internal(const char *classname, int create)
bus_data_generation_update();
}
+ if (parentname && dc && !dc->parent) {
+ dc->parent = devclass_find_internal(parentname, 0, FALSE);
+ }
return (dc);
}
@@ -542,13 +548,13 @@ devclass_find_internal(const char *classname, int create)
devclass_t
devclass_create(const char *classname)
{
- return (devclass_find_internal(classname, TRUE));
+ return (devclass_find_internal(classname, 0, TRUE));
}
devclass_t
devclass_find(const char *classname)
{
- return (devclass_find_internal(classname, FALSE));
+ return (devclass_find_internal(classname, 0, FALSE));
}
int
@@ -574,7 +580,7 @@ devclass_add_driver(devclass_t dc, driver_t *driver)
/*
* Make sure the devclass which the driver is implementing exists.
*/
- devclass_find_internal(driver->name, TRUE);
+ devclass_find_internal(driver->name, 0, TRUE);
dl->driver = driver;
TAILQ_INSERT_TAIL(&dc->drivers, dl, link);
@@ -668,7 +674,7 @@ devclass_find_driver_internal(devclass_t dc, const char *classname)
return (NULL);
}
-driver_t *
+kobj_class_t
devclass_find_driver(devclass_t dc, const char *classname)
{
driverlink_t dl;
@@ -751,6 +757,18 @@ devclass_find_free_unit(devclass_t dc, int unit)
return (unit);
}
+void
+devclass_set_parent(devclass_t dc, devclass_t pdc)
+{
+ dc->parent = pdc;
+}
+
+devclass_t
+devclass_get_parent(devclass_t dc)
+{
+ return (dc->parent);
+}
+
static int
devclass_alloc_unit(devclass_t dc, int *unitp)
{
@@ -857,7 +875,7 @@ make_device(device_t parent, const char *name, int unit)
PDEBUG(("%s at %s as unit %d", name, DEVICENAME(parent), unit));
if (name) {
- dc = devclass_find_internal(name, TRUE);
+ dc = devclass_find_internal(name, 0, TRUE);
if (!dc) {
printf("make_device: can't find device class %s\n",
name);
@@ -1043,44 +1061,54 @@ device_probe_child(device_t dev, device_t child)
if (child->state == DS_ALIVE)
return (0);
- for (dl = first_matching_driver(dc, child);
- dl;
- dl = next_matching_driver(dc, child, dl)) {
- PDEBUG(("Trying %s", DRIVERNAME(dl->driver)));
- device_set_driver(child, dl->driver);
- if (!hasclass)
- device_set_devclass(child, dl->driver->name);
- result = DEVICE_PROBE(child);
- if (!hasclass)
- device_set_devclass(child, 0);
+ for (; dc; dc = dc->parent) {
+ for (dl = first_matching_driver(dc, child);
+ dl;
+ dl = next_matching_driver(dc, child, dl)) {
+ PDEBUG(("Trying %s", DRIVERNAME(dl->driver)));
+ device_set_driver(child, dl->driver);
+ if (!hasclass)
+ device_set_devclass(child, dl->driver->name);
+ result = DEVICE_PROBE(child);
+ if (!hasclass)
+ device_set_devclass(child, 0);
- /*
- * If the driver returns SUCCESS, there can be no higher match
- * for this device.
- */
- if (result == 0) {
- best = dl;
- pri = 0;
- break;
- }
+ /*
+ * If the driver returns SUCCESS, there can be
+ * no higher match for this device.
+ */
+ if (result == 0) {
+ best = dl;
+ pri = 0;
+ break;
+ }
- /*
- * The driver returned an error so it certainly doesn't match.
- */
- if (result > 0) {
- device_set_driver(child, 0);
- continue;
- }
+ /*
+ * The driver returned an error so it
+ * certainly doesn't match.
+ */
+ if (result > 0) {
+ device_set_driver(child, 0);
+ continue;
+ }
+ /*
+ * A priority lower than SUCCESS, remember the
+ * best matching driver. Initialise the value
+ * of pri for the first match.
+ */
+ if (best == 0 || result > pri) {
+ best = dl;
+ pri = result;
+ continue;
+ }
+ }
/*
- * A priority lower than SUCCESS, remember the best matching
- * driver. Initialise the value of pri for the first match.
+ * If we have an unambiguous match in this devclass,
+ * don't look in the parent.
*/
- if (best == 0 || result > pri) {
- best = dl;
- pri = result;
- continue;
- }
+ if (best && pri == 0)
+ break;
}
/*
@@ -1377,7 +1405,7 @@ device_set_devclass(device_t dev, const char *classname)
return (EINVAL);
}
- dc = devclass_find_internal(classname, TRUE);
+ dc = devclass_find_internal(classname, 0, TRUE);
if (!dc)
return (ENOMEM);
@@ -2242,7 +2270,7 @@ root_bus_module_handler(module_t mod, int what, void* arg)
kobj_init((kobj_t) root_bus, (kobj_class_t) &root_driver);
root_bus->driver = &root_driver;
root_bus->state = DS_ATTACHED;
- root_devclass = devclass_find_internal("root", FALSE);
+ root_devclass = devclass_find_internal("root", 0, FALSE);
devinit();
return (0);
@@ -2276,12 +2304,13 @@ root_bus_configure(void)
int
driver_module_handler(module_t mod, int what, void *arg)
{
- int error, i;
+ int error;
struct driver_module_data *dmd;
devclass_t bus_devclass;
+ kobj_class_t driver;
dmd = (struct driver_module_data *)arg;
- bus_devclass = devclass_find_internal(dmd->dmd_busname, TRUE);
+ bus_devclass = devclass_find_internal(dmd->dmd_busname, 0, TRUE);
error = 0;
switch (what) {
@@ -2289,31 +2318,38 @@ driver_module_handler(module_t mod, int what, void *arg)
if (dmd->dmd_chainevh)
error = dmd->dmd_chainevh(mod,what,dmd->dmd_chainarg);
- for (i = 0; !error && i < dmd->dmd_ndrivers; i++) {
- PDEBUG(("Loading module: driver %s on bus %s",
- DRIVERNAME(dmd->dmd_drivers[i]), dmd->dmd_busname));
- error = devclass_add_driver(bus_devclass,
- dmd->dmd_drivers[i]);
- }
+ driver = dmd->dmd_driver;
+ PDEBUG(("Loading module: driver %s on bus %s",
+ DRIVERNAME(driver), dmd->dmd_busname));
+ error = devclass_add_driver(bus_devclass, driver);
if (error)
break;
/*
- * The drivers loaded in this way are assumed to all
- * implement the same devclass.
+ * If the driver has any base classes, make the
+ * devclass inherit from the devclass of the driver's
+ * first base class. This will allow the system to
+ * search for drivers in both devclasses for children
+ * of a device using this driver.
*/
- *dmd->dmd_devclass =
- devclass_find_internal(dmd->dmd_drivers[0]->name, TRUE);
+ if (driver->baseclasses) {
+ const char *parentname;
+ parentname = driver->baseclasses[0]->name;
+ *dmd->dmd_devclass =
+ devclass_find_internal(driver->name,
+ parentname, TRUE);
+ } else {
+ *dmd->dmd_devclass =
+ devclass_find_internal(driver->name, 0, TRUE);
+ }
break;
case MOD_UNLOAD:
- for (i = 0; !error && i < dmd->dmd_ndrivers; i++) {
- PDEBUG(("Unloading module: driver %s from bus %s",
- DRIVERNAME(dmd->dmd_drivers[i]),
- dmd->dmd_busname));
- error = devclass_delete_driver(bus_devclass,
- dmd->dmd_drivers[i]);
- }
+ PDEBUG(("Unloading module: driver %s from bus %s",
+ DRIVERNAME(dmd->dmd_driver),
+ dmd->dmd_busname));
+ error = devclass_delete_driver(bus_devclass,
+ dmd->dmd_driver);
if (!error && dmd->dmd_chainevh)
error = dmd->dmd_chainevh(mod,what,dmd->dmd_chainarg);
diff --git a/sys/kern/subr_kobj.c b/sys/kern/subr_kobj.c
index a3fc230..1704a0f 100644
--- a/sys/kern/subr_kobj.c
+++ b/sys/kern/subr_kobj.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2000 Doug Rabson
+ * Copyright (c) 2000,2003 Doug Rabson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -28,16 +28,15 @@
__FBSDID("$FreeBSD$");
#include <sys/param.h>
-#include <sys/queue.h>
-#include <sys/malloc.h>
#include <sys/kernel.h>
-#include <sys/module.h>
-#include <sys/errno.h>
+#include <sys/kobj.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
#include <sys/sysctl.h>
#ifndef TEST
#include <sys/systm.h>
#endif
-#include <sys/kobj.h>
#ifdef TEST
#include "usertest.h"
@@ -57,22 +56,43 @@ SYSCTL_UINT(_kern, OID_AUTO, kobj_misses, CTLFLAG_RD,
#endif
+static struct mtx kobj_mtx;
static int kobj_next_id = 1;
SYSCTL_UINT(_kern, OID_AUTO, kobj_methodcount, CTLFLAG_RD,
&kobj_next_id, 0, "");
-static int
+static void
+kobj_init_mutex(void *arg)
+{
+
+ mtx_init(&kobj_mtx, "kobj", NULL, MTX_DEF);
+}
+
+SYSINIT(kobj, SI_SUB_LOCK, SI_ORDER_ANY, kobj_init_mutex, NULL);
+
+/*
+ * This method structure is used to initialise new caches. Since the
+ * desc pointer is NULL, it is guaranteed never to match any read
+ * descriptors.
+ */
+static struct kobj_method null_method = {
+ 0, 0,
+};
+
+int
kobj_error_method(void)
{
+
return ENXIO;
}
static void
kobj_register_method(struct kobjop_desc *desc)
{
+
+ mtx_assert(&kobj_mtx, MA_OWNED);
if (desc->id == 0) {
- KASSERT((kobj_next_id < KOBJ_CACHE_SIZE), ("kobj method table overflow"));
desc->id = kobj_next_id++;
}
}
@@ -88,6 +108,8 @@ kobj_class_compile_common(kobj_class_t cls, kobj_ops_t ops)
kobj_method_t *m;
int i;
+ mtx_assert(&kobj_mtx, MA_OWNED);
+
/*
* Don't do anything if we are already compiled.
*/
@@ -103,7 +125,8 @@ kobj_class_compile_common(kobj_class_t cls, kobj_ops_t ops)
/*
* Then initialise the ops table.
*/
- bzero(ops, sizeof(struct kobj_ops));
+ for (i = 0; i < KOBJ_CACHE_SIZE; i++)
+ ops->cache[i] = &null_method;
ops->cls = cls;
cls->ops = ops;
}
@@ -113,42 +136,106 @@ kobj_class_compile(kobj_class_t cls)
{
kobj_ops_t ops;
+ mtx_assert(&kobj_mtx, MA_NOTOWNED);
+
/*
* Allocate space for the compiled ops table.
*/
ops = malloc(sizeof(struct kobj_ops), M_KOBJ, M_NOWAIT);
if (!ops)
panic("kobj_compile_methods: out of memory");
+
+ mtx_lock(&kobj_mtx);
+
+ /*
+ * We may have lost a race for kobj_class_compile here - check
+ * to make sure someone else hasn't already compiled this
+ * class.
+ */
+ if (cls->ops) {
+ mtx_unlock(&kobj_mtx);
+ free(ops, M_KOBJ);
+ return;
+ }
+
kobj_class_compile_common(cls, ops);
+ mtx_unlock(&kobj_mtx);
}
void
kobj_class_compile_static(kobj_class_t cls, kobj_ops_t ops)
{
+
+ mtx_assert(&kobj_mtx, MA_NOTOWNED);
+
/*
* Increment refs to make sure that the ops table is not freed.
*/
+ mtx_lock(&kobj_mtx);
cls->refs++;
kobj_class_compile_common(cls, ops);
+ mtx_unlock(&kobj_mtx);
}
-void
-kobj_lookup_method(kobj_method_t *methods,
- kobj_method_t *ce,
- kobjop_desc_t desc)
+static kobj_method_t*
+kobj_lookup_method_class(kobj_class_t cls, kobjop_desc_t desc)
{
- ce->desc = desc;
- for (; methods && methods->desc; methods++) {
- if (methods->desc == desc) {
- ce->func = methods->func;
- return;
+ kobj_method_t *methods = cls->methods;
+ kobj_method_t *ce;
+
+ for (ce = methods; ce && ce->desc; ce++) {
+ if (ce->desc == desc) {
+ return ce;
}
}
- if (desc->deflt)
- ce->func = desc->deflt;
- else
- ce->func = kobj_error_method;
- return;
+
+ return 0;
+}
+
+static kobj_method_t*
+kobj_lookup_method_mi(kobj_class_t cls,
+ kobjop_desc_t desc)
+{
+ kobj_method_t *ce;
+ kobj_class_t *basep;
+
+ ce = kobj_lookup_method_class(cls, desc);
+ if (ce)
+ return ce;
+
+ basep = cls->baseclasses;
+ if (basep) {
+ for (; *basep; basep++) {
+ ce = kobj_lookup_method_mi(*basep, desc);
+ if (ce)
+ return ce;
+ }
+ }
+
+ return 0;
+}
+
+kobj_method_t*
+kobj_lookup_method(kobj_class_t cls,
+ kobj_method_t **cep,
+ kobjop_desc_t desc)
+{
+ kobj_method_t *ce;
+
+#ifdef KOBJ_STATS
+ /*
+ * Correct for the 'hit' assumption in KOBJOPLOOKUP and record
+ * a 'miss'.
+ */
+ kobj_lookup_hits--;
+ kobj_lookup_misses--;
+#endif
+
+ ce = kobj_lookup_method_mi(cls, desc);
+ if (!ce)
+ ce = desc->deflt;
+ *cep = ce;
+ return ce;
}
void
@@ -156,18 +243,33 @@ kobj_class_free(kobj_class_t cls)
{
int i;
kobj_method_t *m;
+ void* ops = 0;
- /*
- * Unregister any methods which are no longer used.
- */
- for (i = 0, m = cls->methods; m->desc; i++, m++)
- kobj_unregister_method(m->desc);
+ mtx_assert(&kobj_mtx, MA_NOTOWNED);
+ mtx_lock(&kobj_mtx);
/*
- * Free memory and clean up.
+ * Protect against a race between kobj_create and
+ * kobj_delete.
*/
- free(cls->ops, M_KOBJ);
- cls->ops = 0;
+ if (cls->refs == 0) {
+ /*
+ * Unregister any methods which are no longer used.
+ */
+ for (i = 0, m = cls->methods; m->desc; i++, m++)
+ kobj_unregister_method(m->desc);
+
+ /*
+ * Free memory and clean up.
+ */
+ ops = cls->ops;
+ cls->ops = 0;
+ }
+
+ mtx_unlock(&kobj_mtx);
+
+ if (ops)
+ free(ops, M_KOBJ);
}
kobj_t
@@ -191,28 +293,48 @@ kobj_create(kobj_class_t cls,
void
kobj_init(kobj_t obj, kobj_class_t cls)
{
+ mtx_assert(&kobj_mtx, MA_NOTOWNED);
+ retry:
+ mtx_lock(&kobj_mtx);
+
/*
* Consider compiling the class' method table.
*/
- if (!cls->ops)
+ if (!cls->ops) {
+ /*
+ * kobj_class_compile doesn't want the lock held
+ * because of the call to malloc - we drop the lock
+ * and re-try.
+ */
+ mtx_unlock(&kobj_mtx);
kobj_class_compile(cls);
+ goto retry;
+ }
obj->ops = cls->ops;
cls->refs++;
+
+ mtx_unlock(&kobj_mtx);
}
void
kobj_delete(kobj_t obj, struct malloc_type *mtype)
{
kobj_class_t cls = obj->ops->cls;
+ int refs;
/*
* Consider freeing the compiled method table for the class
* after its last instance is deleted. As an optimisation, we
* should defer this for a short while to avoid thrashing.
*/
+ mtx_assert(&kobj_mtx, MA_NOTOWNED);
+ mtx_lock(&kobj_mtx);
cls->refs--;
- if (!cls->refs)
+ refs = cls->refs;
+ mtx_unlock(&kobj_mtx);
+
+ if (!refs)
kobj_class_free(cls);
obj->ops = 0;
diff --git a/sys/sys/bus.h b/sys/sys/bus.h
index e5bdd85..7e69b2c 100644
--- a/sys/sys/bus.h
+++ b/sys/sys/bus.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1997,1998 Doug Rabson
+ * Copyright (c) 1997,1998,2003 Doug Rabson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -75,7 +75,7 @@ struct u_device {
* Forward declarations
*/
typedef struct device *device_t;
-typedef struct driver driver_t;
+typedef struct kobj_class driver_t;
typedef struct devclass *devclass_t;
#define device_method_t kobj_method_t
@@ -124,9 +124,12 @@ enum intr_polarity {
typedef int (*devop_t)(void);
+/*
+ * This structure is deprecated. Use the kobj(9) macro DEFINE_CLASS to
+ * declare classes which implement device drivers.
+ */
struct driver {
KOBJ_CLASS_FIELDS;
- void *priv; /* driver private data */
};
/*
@@ -345,17 +348,19 @@ void device_verbose(device_t dev);
/*
* Access functions for devclass.
*/
-int devclass_add_driver(devclass_t dc, driver_t *driver);
-int devclass_delete_driver(devclass_t dc, driver_t *driver);
+int devclass_add_driver(devclass_t dc, kobj_class_t driver);
+int devclass_delete_driver(devclass_t dc, kobj_class_t driver);
devclass_t devclass_create(const char *classname);
devclass_t devclass_find(const char *classname);
-driver_t *devclass_find_driver(devclass_t dc, const char *classname);
+kobj_class_t devclass_find_driver(devclass_t dc, const char *classname);
const char *devclass_get_name(devclass_t dc);
device_t devclass_get_device(devclass_t dc, int unit);
void *devclass_get_softc(devclass_t dc, int unit);
int devclass_get_devices(devclass_t dc, device_t **listp, int *countp);
int devclass_get_maxunit(devclass_t dc);
int devclass_find_free_unit(devclass_t dc, int unit);
+void devclass_set_parent(devclass_t dc, devclass_t pdc);
+devclass_t devclass_get_parent(devclass_t dc);
/*
* Access functions for device resources.
@@ -407,40 +412,16 @@ struct driver_module_data {
int (*dmd_chainevh)(struct module *, int, void *);
void *dmd_chainarg;
const char *dmd_busname;
- driver_t **dmd_drivers;
- int dmd_ndrivers;
+ kobj_class_t dmd_driver;
devclass_t *dmd_devclass;
};
#define DRIVER_MODULE(name, busname, driver, devclass, evh, arg) \
\
-static driver_t *name##_##busname##_driver_list[] = { &driver }; \
-static struct driver_module_data name##_##busname##_driver_mod = { \
- evh, arg, \
- #busname, \
- name##_##busname##_driver_list, \
- (sizeof name##_##busname##_driver_list) / \
- (sizeof name##_##busname##_driver_list[0]), \
- &devclass \
-}; \
- \
-static moduledata_t name##_##busname##_mod = { \
- #busname "/" #name, \
- driver_module_handler, \
- &name##_##busname##_driver_mod \
-}; \
-DECLARE_MODULE(name##_##busname, name##_##busname##_mod, \
- SI_SUB_DRIVERS, SI_ORDER_MIDDLE)
-
-#define MULTI_DRIVER_MODULE(name, busname, drivers, devclass, evh, arg) \
- \
-static driver_t name##_##busname##_driver_list[] = drivers; \
static struct driver_module_data name##_##busname##_driver_mod = { \
evh, arg, \
#busname, \
- name##_##busname##_driver_list, \
- (sizeof name##_##busname##_driver_list) / \
- (sizeof name##_##busname##_driver_list[0]), \
+ (kobj_class_t) &driver, \
&devclass \
}; \
\
diff --git a/sys/sys/kobj.h b/sys/sys/kobj.h
index 2a7ebbb..d2cd0da 100644
--- a/sys/sys/kobj.h
+++ b/sys/sys/kobj.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2000 Doug Rabson
+ * Copyright (c) 2000,2003 Doug Rabson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -55,6 +55,7 @@ struct kobj_method {
const char *name; /* class name */ \
kobj_method_t *methods; /* method table */ \
size_t size; /* object size */ \
+ kobj_class_t *baseclasses; /* base classes */ \
u_int refs; /* reference count */ \
kobj_ops_t ops /* compiled method table */
@@ -79,13 +80,13 @@ struct kobj {
#define KOBJ_CACHE_SIZE 256
struct kobj_ops {
- kobj_method_t cache[KOBJ_CACHE_SIZE];
+ kobj_method_t *cache[KOBJ_CACHE_SIZE];
kobj_class_t cls;
};
struct kobjop_desc {
- unsigned int id; /* unique ID */
- kobjop_t deflt; /* default implementation */
+ unsigned int id; /* unique ID */
+ kobj_method_t *deflt; /* default implementation */
};
/*
@@ -93,13 +94,79 @@ struct kobjop_desc {
*/
#define KOBJMETHOD(NAME, FUNC) { &NAME##_desc, (kobjop_t) FUNC }
-#define DEFINE_CLASS(name, methods, size) \
- \
-struct kobj_class name ## _class = { \
- #name, methods, size \
+/*
+ * Declare a class (which should be defined in another file.
+ */
+#define DECLARE_CLASS(name) extern struct kobj_class name
+
+/*
+ * Define a class with no base classes (api backward-compatible. with
+ * FreeBSD-5.1 and earlier).
+ */
+#define DEFINE_CLASS(name, methods, size) \
+DEFINE_CLASS_0(name, name ## _class, methods, size)
+
+/*
+ * Define a class with no base classes. Use like this:
+ *
+ * DEFINE_CLASS_0(foo, foo_class, foo_methods, sizeof(foo_softc));
+ */
+#define DEFINE_CLASS_0(name, classvar, methods, size) \
+ \
+struct kobj_class classvar = { \
+ #name, methods, size, 0 \
+}
+
+/*
+ * Define a class inheriting a single base class. Use like this:
+ *
+ * DEFINE_CLASS1(foo, foo_class, foo_methods, sizeof(foo_softc),
+ * bar);
+ */
+#define DEFINE_CLASS_1(name, classvar, methods, size, \
+ base1) \
+ \
+static kobj_class_t name ## _baseclasses[] = \
+ { &base1, 0 }; \
+struct kobj_class classvar = { \
+ #name, methods, size, name ## _baseclasses \
+}
+
+/*
+ * Define a class inheriting two base classes. Use like this:
+ *
+ * DEFINE_CLASS2(foo, foo_class, foo_methods, sizeof(foo_softc),
+ * bar, baz);
+ */
+#define DEFINE_CLASS_2(name, methods, size, \
+ base1, base2) \
+ \
+static kobj_class_t name ## _baseclasses[] = \
+ { &base1, \
+ &base2, 0 }; \
+struct kobj_class name ## _class = { \
+ #name, methods, size, name ## _baseclasses \
}
/*
+ * Define a class inheriting three base classes. Use like this:
+ *
+ * DEFINE_CLASS3(foo, foo_class, foo_methods, sizeof(foo_softc),
+ * bar, baz, foobar);
+ */
+#define DEFINE_CLASS_3(name, methods, size, \
+ base1, base2, base3) \
+ \
+static kobj_class_t name ## _baseclasses[] = \
+ { &base1, \
+ &base2, \
+ &base3, 0 }; \
+struct kobj_class name ## _class = { \
+ #name, methods, size, name ## _baseclasses \
+}
+
+
+/*
* Compile the method table in a class.
*/
void kobj_class_compile(kobj_class_t cls);
@@ -145,31 +212,38 @@ extern u_int kobj_lookup_misses;
* slow way.
*/
#ifdef KOBJ_STATS
-#define KOBJOPLOOKUP(OPS,OP) do { \
- kobjop_desc_t _desc = &OP##_##desc; \
- kobj_method_t *_ce = \
- &OPS->cache[_desc->id & (KOBJ_CACHE_SIZE-1)]; \
- if (_ce->desc != _desc) { \
- kobj_lookup_misses++; \
- kobj_lookup_method(OPS->cls->methods, _ce, _desc); \
- } else { \
- kobj_lookup_hits++; \
- } \
- _m = _ce->func; \
+#define KOBJOPLOOKUP(OPS,OP) do { \
+ kobjop_desc_t _desc = &OP##_##desc; \
+ kobj_method_t **_cep = \
+ &OPS->cache[_desc->id & (KOBJ_CACHE_SIZE-1)]; \
+ kobj_method_t *_ce = *_cep; \
+ kobj_lookup_hits++; /* assume hit */ \
+ if (_ce->desc != _desc) \
+ _ce = kobj_lookup_method(OPS->cls, \
+ _cep, _desc); \
+ _m = _ce->func; \
} while(0)
-#else /* !KOBJ_STATS */
-#define KOBJOPLOOKUP(OPS,OP) do { \
- kobjop_desc_t _desc = &OP##_##desc; \
- kobj_method_t *_ce = \
- &OPS->cache[_desc->id & (KOBJ_CACHE_SIZE-1)]; \
- if (_ce->desc != _desc) \
- kobj_lookup_method(OPS->cls->methods, _ce, _desc); \
- _m = _ce->func; \
+#else
+#define KOBJOPLOOKUP(OPS,OP) do { \
+ kobjop_desc_t _desc = &OP##_##desc; \
+ kobj_method_t **_cep = \
+ &OPS->cache[_desc->id & (KOBJ_CACHE_SIZE-1)]; \
+ kobj_method_t *_ce = *_cep; \
+ if (_ce->desc != _desc) \
+ _ce = kobj_lookup_method(OPS->cls, \
+ _cep, _desc); \
+ _m = _ce->func; \
} while(0)
-#endif /* !KOBJ_STATS */
+#endif
+
+kobj_method_t* kobj_lookup_method(kobj_class_t cls,
+ kobj_method_t **cep,
+ kobjop_desc_t desc);
-void kobj_lookup_method(kobj_method_t *methods,
- kobj_method_t *ce,
- kobjop_desc_t desc);
+
+/*
+ * Default method implementation. Returns ENXIO.
+ */
+int kobj_error_method(void);
#endif /* !_SYS_KOBJ_H_ */
diff --git a/sys/sys/param.h b/sys/sys/param.h
index 8ae8434..42e242c 100644
--- a/sys/sys/param.h
+++ b/sys/sys/param.h
@@ -57,7 +57,7 @@
* scheme is: <major><two digit minor><0 if release branch, otherwise 1>xx
*/
#undef __FreeBSD_version
-#define __FreeBSD_version 501111 /* Master, propagated to newvers */
+#define __FreeBSD_version 501112 /* Master, propagated to newvers */
#ifndef NULL
#define NULL 0
OpenPOWER on IntegriCloud