Subject: Re: dynamic configuration (was Re: PR#4094)
To: Frank van der Linden <fvdl@wasabisystems.com>
From: Chris G. Demetriou <cgd@sibyte.com>
List: tech-kern
Date: 08/10/2000 16:26:00
Frank van der Linden <fvdl@wasabisystems.com> writes:
> More error prone? Why? In fact, I think it's a lot better.

because it involves humans writing code, and then updating code when
the method to call the init function changes, etc.  Humans are
notoriously unreliable and bug-prone.

("Indeed, every computer bug can be attributed to a human!" 8-)

Computer programs, be they toolchains or other, are deterministic
(unless you make a strong attempt to make them otherwise).  Even most
random numbers aren't.


> I do NOT
> want to have a kernel in which initialization is done in an order
> unknown to me, and be at the mercy of the toolchain. I prefer
> to do this in a controlled fashion. Not to mention that it makes
> debugging harder.

So, the way i've proposed this is that:

(1) each 'set of stuff' is done independently of the other, i.e. you
can be safe knowing that all malloc types have been initted before any
other malloc types have.

(2) the initialization for each element of each set of types is
_absolutely independent_ of every other element of that set.  I.e. the
operations to be performed are not in any way dependent on a previous
member of the set.

There may be some minor differences in ordering, e.g. the order that
things get put on a linked list.  But i see no reason why anybody
should consider that a problem.  Even if things get randomly reordered
when you build a new kernel (and, in fact, that's not what would
happen; the behaviour is quite deterministic, based on order of .o
files), if the kernel falls over because of ordering of elements on an
unsorted linked list... that's an indication of something Very Broken.

You're already at the mercy of your toolchain if you're compiling a
kernel.  The only potential problems come up as a result of linker
bugs, and as a result of changed interfaces not causing recompilation.
If the former are commonplace -- i.e. if they happen more than
O(never) -- then that's something to consider... but it more seriously
impacts the usability of NetBSD in general.  If you can't trust your
linker to link programs... you're screwed anyway.  The latter are
pretty much a non-issue; make depend should handle that, and, again,
if for some reason it does not then you've got some Serious problem,
or at worst can make clean and remake your .o files.

Another way to look at this: you have to trust something either way.
i'd rather trust code (the toolchain) that gets a frequent workout on
a wide variety of input, and which is actually regression tested by
some people, than code (e.g. config) which is not well documented,
quite a ball of hair inside, and is not particularly thoroughly
tested.


Also, I'd like to know how, in fact, it makes debugging harder on an
ongoing basis.  If your assumption is "before the init routine for
this particular class of thing is used, it's unusable, and after the
routine finishes it is," there's no additional debugging (assuming the
routine actually functions properly).  There may be debugging of the
init routine itself, but that should be a limited cost effort up
front, both because of the simpilicity and hopefully the lack of
change in the interface.  "Don't use facilities that you've not yet
initialized."

I can think of some things, e.g. instead of getting a number for an M_
type, you get a pointer.  however, the M_* name will be associated
with that pointer's address, so debuggers that don't suck will do the
right thing.  And if you need to look for stats or the data associated
with the particular object you're accessing, of course, the data's
right there, no more indexing of arrays or tables to find it.


> That's exactly why using global constructors in C++ can be a disaster,
> you never know what has been initialized and what not.

Right.  An issue if you can have interdependencies among the
constructors, but not an issue here.


Some more clarification:

The intent is that the initialization of each type be done at a 'known
time' at kernel start.  e.g. the init of the malloc types could be
done at malloc init time, the fs init could be done at vfs init time,
and the device table init could be done before autoconfiguration.

Fish aside, dealing with this type of initialization ordering issue is
simply not a problem in the kernel.  Kernel programmers (who do
low-level MD init code hacking) know that there's a time before it's
safe to use malloc, that there's a time before you can use file system
or device functions, or many other general kernel services.  This is
no different than that.  Kernel programmers who do not do that hacking
don't -- and still won't -- need to worry about it.



btw, another on the list of things this applies to: when sysctl is
dynamic, and based on strings, this would apply to registration of
sysctl nodes as well.

(finally, I think that it's really desirable to add 'end caps' used by
these lists to the kernel, regardless of their use for this purpose.
in particular, you need them if you want to support actual ctors, and,
while i'm sure you mostly wouldn't want to do that, it is useful in
that it allows you to put standard gcc code coverage data collection
into the kernel... and some people find that type of thing valuable.)


cgd