Okay, either I misunderstood what you were asking in the first place, or
I didn't explain my idea very well. I think I'll try again.
You have a module library, part of the kernel, consisting of primarily
allocators. I'll call this mlib.
You have an actual module. This is a loadable piece of code and data,
that probably (we'll assume it does) allocates data at some point, and
provides a service to the rest of the kernel. This service can be in
the form of code or data or both.
The problem is, as I see it, this: How do you unload (and free) the
module, while parts of the kernel may be using the module. If you were
to do this, then whatever part of the kernel is using some module
service would fail the next time it tried to use it.
I propose that the mlib provide a struct handle, which consists of a
pointer to the module that owns handle, a refcount, and a function
pointer. When the kernel wants to use a service provided by the module,
it calls into the mlib to allocate a handle. This will create the handle
if one doesn't exist for the service, or increment the refcount if the
handle exists. Then, the kernel can use the function pointer to access
the service provided by the module. There would be a seperate handle
for each service.
When the module wants to unload, it does a series of steps. First, it
sets a flag that causes all uses of the function pointer in all it's
handles to return failure. Then, it waits for any already-in-use handle
to be finished. Finally, it asks mlib to unlink all it's handles. They
will continue to exist, but the function pointers will point to a dummy
function (in the mlib) that returns error. At this point, nothing
outside the module has any pointer to anything inside the module, and
the module can be safely unloaded.
When a handle returns "Module unavailable", the caller should release
it's handle. This will decrement the refcount. When the refcount on a
handle goes to 0, the handle can be freed, by the mlib. This guarantees
that all handles will eventually be freed.
All this requires is that all calls into modules (via the handle) must
be checked for error return. We always check the return value of all
functions anyway, right? :)
Any cookies provided by the module (be they pointers or bit vectors, or
whatever) have meaning only to that module, so it doesn't matter if they
continue to exist after the module is gone, as they should never be used
except to pass into the module, and once the module is gone, that cannot
happen. Any data allocated by the module is freed by the module when it
is unloaded, and should never be referenced outside the module, so
that's not a problem. Handles are not allocated, freed, or owned by the
module, but by the mlib, so that's not an issue with module removal.
As far as I can see, this should work, and should be quite fast. There
may be better ways, but every access to any module *must* be checked, if
you ever want to unload the module.
On Mon, 2003-06-30 at 20:39, William Rose wrote:
> > The real solution is proper module boundaries. Nothing outside a module
> > has a pointer to anything inside the modules. Ever. Under any
> > circumstances. A referenced counted handle to the module itself is
> > obtained, and used for all interation with the modules (and it has
> > function pointers and so on. Like a lite class structure).
> I don't see how this solves the problem.
> AFAIK, in the current kernel, the only pointers stored by the kernel to
> things inside a module are pointers the module itself allocates. This is
> so that one module can create many objects (e.g. net interfaces, file
> systems, device nodes, file cookies). Unless you create a copy of the
> module for each time you make an object, you will have to give the kernel
> some way of signalling to the module which object it is referring to.
> This reference may as well be a pointer, because there will still be
> issues with whether it is still valid regardless (even if it is used as a
> handle, its validity has to be confirmed before every use).
> > It is
> > allocated when first requested, and freed when it's reference count goes
> > to zero, by non-module code (ie by some kernal library). When the
> > module goes away, all uses of the handle return an error.
> Is the idea that the module's lifetime will therefore be guaranteed to be
> longer than the objects it creates? And that this means that there will
> be no dangling references? Achieving the latter still requires that the
> module consider the external lifetime of pointers it allocates, and
> glosses over the original problem of how the module handles a delete
> request when not all of the references to an object have been released
> (without tracking those references i.e. garbage collecting).
> > This way, the
> > module only needs to track when code within it is actually being used,
> > not all external pointers to the code.
> > As long as no one is currently
> > in the module, it can safely mark itself offline (causing all handle use
> > to return an error), and proceed to free all it's memory and delete
> > itself (or rather ask the module support library to delete it). All the
> > handles will safely go away when the last user is done with them.
> I think the approach you are outlining essentially boils down to using
> handles to objects inside modules rather than pointers. As I asked in my
> original post, is this the best approach? Now everyone must check their
> handle every time they use it? Only now you've also made sure that the
> function pointers to modules are accessed via a handle as well?
> I feel like I'm missing the good bit ;-)
> This SF.Net email sponsored by: Free pre-built ASP.NET sites including
> Data Reports, E-commerce, Portals, and Forums are available now.
> Download today and enter to win an XBOX or Visual Studio .NET.
> Syllable-developer mailing list
Daniel Gryniewicz <dang@...>