Originally the object system was just used for file, directory and symlink objects, but I extended it so that references to objects can be exported to other processes using Plash's object-capability protocol. There are other kinds of object now.
An object reference has type "struct filesys_obj *". "cap_t" is an alias for this.
There are a number of methods defined. Every object supports all the methods. That is, it is valid to call a method on any object, even if the method isn't relevant to that object. If the method isn't relevant, it will return an error code (for those methods that can return error codes).
Every object contains a pointer to a vtable, which contains function pointers implementing the methods. This design is simple, but it means all the vtables need to be recompiled when we add new methods. Since the vtables are sparse (ie. most methods aren't relevant to a given object), we have a program, "make-vtables.pl", which generates the C code for constructing the vtables.
All objects have a reference count. To increment the count, use "inc_ref(obj)". To decrement the count, use "filesys_obj_free(obj)" (this will free the object when the count hits zero). Some references are owning references -- you are supposed to free them. Some references are non-owning -- they are "borrowed" from the caller.
The choice of whether a function argument is an owning or a non-owning reference is based on a trade-off between convenience and minimising the lifetime of objects. You have to look at the comments for a function to see whether its arguments are passed as owning or non-owning.
In order to make a method call across a connection using the object-capability protocol, the method's arguments must be marshalled -- converted into a string and an array of objects/FDs, and then converted back again at the other end.
Marshalled arguments are represented by "struct cap_args".
The most general methods are "cap_invoke" and "cap_call", which only use marshalled arguments. "cap_invoke" is send-only and asynchronous; it returns immediately and does not itself get a reply. "cap_call" is synchronous and returns a result.
The other methods call, or are called by, "cap_call".
For remote objects, other methods marshal their arguments and call "cap_call", which in turn calls "cap_invoke".
When local objects receive a remote request, "cap_invoke" handles this request and calls "cap_call", which unmarshals the arguments and calls the relevant method.
The reason the other methods exist is that they are more efficient to use for calls within a process, and they are more convenient.
For some methods, marshalling is not implemented, so these methods can't be used remotely.