- We're talking about a really minimalistic microkernel -- no kernel-mode drivers or modules of any kind. This means all the code is written/maintained/known by one team (currently one person). It should also mean, in theory, that all control paths are well-known and behave predictably, especially in terms of memory usage.
- There are two kinds of object lifetimes in such a microkernel -- those that must persist between kernel invocations and those that do not (examples below).
- The kernel programming style used lends itself to small, transient, dynamically allocated objects (this is a big assumption that may be invalidated before I'm through).
- Dynamically allocated strings (rare, I know, but possible -- perhaps used when formatting output for debugging).
- Polymorphic objects that encapsulate behaviour within the kernel that varies at run-time. It's hard to think of a concrete example right now -- I'm early in coding and haven't fully forseen the need for such things. I'll just throw out one possibility -- imagine something similar to std::ostream in C++ that could output to either the screen (vgastream?) or a serial port (serialstream?), depending on whether a remote kernel debugger is active.
Anyway, here's the idea: Each thread normally has a large contiguous block of memory for its kernel stack. This block is generally of a fixed size (unlike user-mode stacks, which are usually allowed to grow dynamically by allocating more pages). I'm generalizing here, but bear with me. In order to support the more "persistent" kernel objects, the kernel must have a more or less traditional heap manager (kmalloc/kfree). But, what if the chunk used for the kernel stack could also be used to allocate small temporary objects? A kind of thread-local fast-allocating mini-heap if you will. So for any given thread running in the kernel, its kernel stack would grow downward from the top and its "mini-heap" would grow up from the bottom. Then, when the thread is about to return to user-mode, the "top of heap" pointer is reset to the bottom and all the temporary objects are instantly deallocated (I'm assuming no need for "destructor" or "finalizer"-like constructs here). It's kind of like really cheap special-purpose garbage collection.
First, before the usual avalanche of responses from the seasoned veterans asking whether I'm insane -- allow me to explain how I arrived at this idea. I'm implementing my kernel in C, but I'm designing it in a very OO manner. This is the way I design in "real life", so I want to see how applicable the techniques are in kernel-land. Part of the general pattern of OO implementations is a tendency towards many small dynamically-allocated objects. They are usually dynamically allocated because they are polymorphic and the decision of what their actual type should be is deferred to some factory object. They are usually small because most of the objects in a system are fine-grained "utility classes" that contain very little state (but perhaps a lot of polymorphic behaviour). I don't have enough of an idea yet about the forces that will shape the rest of my kernel's design to know if these traits will be common or not. They're certainly common in middleware, but that's a different world altogether...
So, I have three questions:
- Does anyone think this is workable?
- Does anyone think it is useful?
- If so, can you think of any more example situations in which it would be useful?