design choices for a loadable module interface
Nicolas.Williams at oracle.com
Tue Jun 29 18:56:47 EDT 2010
On Tue, Jun 29, 2010 at 03:19:25PM -0700, Russ Allbery wrote:
> Nicolas Williams <Nicolas.Williams at oracle.com> writes:
> > HOWEVER, just because there is one thing that the linker/loader will not
> > do for us does not mean we should throw the baby out with the bath water
> > and effectively duplicate other linker/loader functionality.
> Could you be more specific about exactly what functionality you see the
> vtable approach as duplicating? I assume you mean something more than
> just writing the struct definition of the vtable, since that's trivial.
That. V-tables need to be written. And they make it harder to read the
source, particularly since you're almost guaranteed to have different
function names in every plugin, so now you have to search for
assignments in cscope. And they're ugly (yes, an aesthetic argument).
> > If you decide to never make backwards-incompatible changes to function
> > signatures and semantics then you there is no need to keep track of
> > anything more with one scheme or the other.
> I believe the chances of successfully holding to such a decision are zero.
> There will be backwards-incompatible changes to function signatures and
> semantics. The framework should plan for them from the start.
Zero because... we can't be expected to not make such a mistake? Or
because you don't want that constraint?
Note that the above constraint applies only if you want to do anything
more than reject plugins that don't export the one API version supported
by the framework. I.e., if you want to support a variety plugins using
different API versions, then you must not make backwards-incompatible
changes to the ABI.
Note that you could make the same kind of mistakes with a versioned
v-table scheme too if you're not careful, especially if you allow
plugins to support more than one version at a time.
> > (1) and (2) really are equivalent, except that (2) requires more work on
> > the part of plugin authors than (1).
> Speaking as a plugin author, the amount of additional work (2) requires is
> not sufficient to warrant calling it additional work (although of course
> just providing a public data symbol is even easier). It's a trivial
> function that one can write in five minutes.
For user-land I much prefer (1); formative experience there includes,
among others, libpam and libgss (see below) (on Solaris).
(For kernel-land... (2) is so common in kernel-land that (2) doesn't
bother me there. Though modern kernel loadable module frameworks are
about as powerful as user-land linker/loaders nowadays, so I see no
reason not to use (1) in kernel-land as well.)
On Solaris libgss uses a non-version v-table for old stuff, dlsym() for
new stuff. Every time we added functions we had to patch libgss and all
plugins together. What a pain. Granted, with a versioned v-table we'd
not have to, but now we'd have N versions of the same crappy structure
lying around, with libgss having to know all N -- that's a lot of
unnecessary duplication and unnecessary code, plus it's ugly. So I just
made it so new additions are dlsym()ed and that's that.
More information about the krbdev