Fix several issues in the slab allocator identified by the heap stress
tests (intermittent) and running the tests under Miri.
1. Fix Undefined Behavior. Previously, the allocator created temporary
`&mut Frame` references while raw pointers to that frame existed in the
intrusive `partial` or `free` lists. Under Miri's strict aliasing rules,
creating a unique reference to the whole struct invalidated the list
pointers.
The fix implements "split borrowing": we now maintain raw pointers to
the frame and only create mutable references to the `.state` field
when needed, ensuring the `.link` field remains valid for the
intrusive list.
2. Fix `free_list_sz` accounting. In `try_alloc`, the `free_list_sz`
counter was not being decremented when a slab was successfully popped
from the free list. This caused the allocator to believe it had free
slabs when the list was actually empty, leading to panics during
batch-free operations.
3. Increase heap stress tests. The test suite now runs the stress test
in a loop to catch state persistence bugs and ensures the allocator is
fully torn down and reset between iterations.
Fixes: #220
Add a new module which implements the high-level heap logic (implements
`GlobalAlloc`) for the slab allocator.
Also implement a multi-threaded stress test of the heap ensuring
concurrent allocation is unique (doesn't corrupt other allocs) and all
memory is free'd back to the `FrameAllocator` when all caches are
purged.
Add a new module for managing objects within a slab. The `Slab` struct
manages objects of a given set within a contiguous set of pages. It is
the handle to the underlying memory, allowing for objects to be
allocated, and free'd. It manages a free list of 'indexes' within the
object slots themselves.
Rather than returning a reference to the `OnceCell` wrapping the
allocator, return a static reference to the allocator itself. This
allows flexibility for how the allocator is wrapped.
Move the FrameList logic out of the physical memory allocator into its
own module. This allows `FrameList` to be shared between the physical
memory allocator and the slab allocator.
Create a new submodule within `memory`, `allocators` which contains all
memory allocators. Also split out the `Frame` struct from the `pg_alloc`
module, allowing it to be used by other modules.
Add the proper inode and fs id to the `FileAttr` struct returned by
`getattr`. This prevents the dynamic loader from skipping files which it
considers to be hard-links (share the same inode ID).
Currently, when a kernel stack overflow occures, the exception handler
blindly attempts to write the current context to the stack. If the SP
isn't valid this causes another fault, and so on - locking up the
system.
This commit re-arranges the stack layout, performs SP validation before
usage and switches to an emergency stack when SP isn't valid. This
allows the handler to run and panic gracefully.
Fixes: #98