This article attempts to explain the kobj interface definition files used by the FreeBSD kernel object system, and how to create a simple object. These .m files If you're in the habit of browsing FreeBSD kernel source you might have noticed these foo_if.m files turning up; something that looks kind of like C, but not really like anything. These define the methods available to objects created with the FreeBSD kernel object system, kobj. kobj is a new programing interface introduced by Doug Rabson, that can give object oriented properties to C code. It is a simple, robust implementation of dynamic method call dispatch which is suitable for use in a kernel environment. The .m files are very similar to the IDL used by corba. There is an interface compiler, makeobjops.pl, which produces inline stub functions that provide the dynamic dispatch glue. These functions serve to call the provided implementation of the method. An interface is defined like this: INTERFACE foo; METHOD void bar { kobj_t baz; }; This defines an interface foo, and a method bar which takes one argument, the kernel object, baz. The argument is analogous to a "this" pointer, other arguments may follow but the first must always be the kernel object. All methods of an interface are prefixed with its name, and then uppercased, so we will call bar as FOO_BAR(baz); To compile this interface put it in a file called foo_if.m and run the interface compiler on it, perl makeobjops.pl -c -h foo_if.m; -c -h specifies produce both .c and .h files. The resulting stub for bar looks like this: extern struct kobjop_desc foo_bar_desc; typedef void foo_bar_t(kobj_t baz); static __inline void FOO_BAR(kobj_t baz) { kobjop_t _m; KOBJOPLOOKUP(((kobj_t)baz)->ops,foo_bar); ((foo_bar_t *) _m)(baz); } The KOBJOPLOOKUP macro finds the implementation of bar in the kernel object's method table, and assigns its address to _m. The actual implementation is then called through the method pointer. The description for bar (foo_bar_desc) is used to uniquely identify the method, and to potentially provide a default implementation. It is defined in the .c file: struct kobjop_desc foo_bar_desc = { 0, (kobjop_t) 0 }; We can provide a default implementation for bar like this: CODE { static void null_bar(kobj_t baz) { printf("you lose!"); } }; METHOD void bar { kobj_t baz; } DEFAULT null_bar; Now the .c file becomes more interesting: static void null_bar(kobj_t baz) { printf("you lose!"); } struct kobjop_desc foo_bar_desc = { 0, (kobjop_t) null_bar }; null_bar will be called in the event that no other implementation is available. Making an object In order to create an object that implements our interface foo, a method table must first be created: static void my_bar(kobj_t baz) { printf("you win!"); } kobj_method_t foo_methods = { /* foo interface */ KOBJMETHOD(bar, my_bar), { 0, 0 } }; Then the provided macro to define a class can be used: DEFINE_CLASS(foo, foo_methods, sizeof(struct kobj)); This defines foo_class as a kobj_class_t, and initializes it to create objects of the specified size, implementing the method(s) in the foo_methods table. A class's method table must be compiled before it can be used, but this is done automatically by the kobj system. An object can now be created with the kobj_create function: kobj_t baz = kobj_create(foo_class, M_FOO, M_WAITOK); This will malloc(9) space for an object as specifed in the class, and initialize it to reference the class's compiled method table. The methods implemented by this object are called with the interface name prefixed, in uppercase: FOO_BAR(baz); The allocated object should be freed with kobj_delete. Crafty objects Above the default object type (kobj_t) was used, but it can be any struct type that contains the necesary fields. A macro is provided for this purpose: struct foo { KOBJ_FIELDS; int foo_secret; }; The foo interface can then be redefined: #include "foo.h" INTERFACE foo; CODE { static void null_bar(struct foo *baz, int secret) { if (secret != baz->foo_secret) printf("you lose!"); } }; METHOD void bar { struct foo *baz; int secret; } DEFAULT null_bar; Since the kernel object is cast to a kobj_t in the KOBJOPLOOKUP macro, the KOBJ_FILEDS must come first in the struct. Static methods Additionally an interface can have static methods, specified with STATICMETHOD, which are called on a class object. Before a static method can be called the class's method table must be compiled. KOBJOPLOOKUP does not check for this, so if the static method is to be called before kobj_create or kobj_init, the table must first be compiled with kobj_class_compile. More Examples More contrived kobj examples can be found here: http://people.freebsd.org/~jake/kobj -- Jake