in practice the hard-OOM only seems to happen, and oom-doom
takes up precious memory that could be used for preventing
OOMs. Just leave one path in, but make it a bit smarter.
The smarts are still in userland, so the kernel is minimal
dependencies.
The Hard OOM re-entrant syscall can actually originate in
any process space, but only from inside the kernel. Modify the
checks so that the PID==2 check is applied only to all the other
calls; and that a supervisor mode check is applied to the hard OOM
call.
turns out that
- hard OOM has a clearly defined threshold: 0. we shouldn't
make it higher, because then it forces us to count free memory
on every allocation.
- it's better to have the tuning in userspace (I think) for
OOM, because that's where all the algorithms are
some thought needs to go into when and how we call oom_doom
but let's test more core functionality of the swapper before we
worry about that. I can think of several places where we could
use that call, the main tricky bit is that oom_doom diverges
and so wherever we patch it has to be able to resume. If we put
it into e.g. somewhere in the main memory alloc loop, the trouble
is we would have to track all of the multiple places that we
could have arrived there...ideally we can find a single spot
to patch this, with a clean entry and exit path.
instead of sending scalar messages on every page alloc/free, which
is a lot of traffic, introduce an API where the swapper can request
a snapshot of the alloc status by mapping the kernel's alloc
table as a read-only structure into the swapper's memory space,
and then invoking the swapper in its interrupt context to read that out.
The structure is unmapped on return from the context.
additionally, a running tally of free space is now maintained
and this can be queried with a fast syscall.
Thus, the normal workflow is the swapper would have a timer that
periodically queries the kernel's free space level, and when it
falls below a critical amount, it will invoke the expensive snapshot.
this can also be extended so that the kernel can call into
the swapper's interrupt context with a "help, OOM imminent"
message down the road.
The unmap syscall is a little bit tricky, because it can de-allocate
several pages at once, which can trigger an advisory de-allocate
message to the swapper in the middle of the loop. The entire structure
has to be re-written to handle this case, so we patch this right at
the top level syscall point and handle it entirely with custom
logic in the swapper.
With Rust 1.76.0, we no longer support building with `#![no_std]` or
`panic = "abort"`, both of which are required within the kernel. As a
workaround, go back to building the kernel under
`riscv32imac-unknown-none-elf`.
Signed-off-by: Sean Cross <sean@xobs.io>
Fix memory zeroing when requesting a physical pointer. Previously, only
the first 25% of a page was zeroed due to a bug when casting between
*mut u8 and *mut usize.
This now uses `write_volatile` to ensure the memory clear isn't
optimized out, and uses `usize` pointers everywhere.
Signed-off-by: Sean Cross <sean@xobs.io>
Even when the print-debug feature isn't turned on, println! macro is still able to output some critical non-debug info to the console such as panics, process crashes and violations, etc. Debugging messages are printed with klog! macro that's disabled when debug-print feature is not set.
The previous patch didn't properly restore thread IDs when switching
contexts -- there were spots where we missed things, and spots where we
were double-borrowing.
Fix these corner cases.
Signed-off-by: Sean Cross <sean@xobs.io>
Note the current thread in the original process when its quantum
expires. This will allow us to clean up after ourselves when a context
switch occurs, and will help to prevent thread starvation.
Signed-off-by: Sean Cross <sean@xobs.io>
Currently, returning a Message (e.g. a Scalar1, Scalar2, or
MemoryMessage) always results in a context switch from the server to the
client. This is what makes these syscalls cheaper.
However, this results in process starvation. For example, if three
processes send a message to a server, then the server will only be able
to respond to one of those messages at a time. This works well with a
lightly-loaded system, but quickly falls apart when many threads are
running.
Keep track of which process and thread were originally switched to as
part of the `SwitchTo` call. If the Server is responding to a message
and owns the current quantum, don't immediately switch to the Client
thread.
Signed-off-by: Sean Cross <sean@xobs.io>
Unify scalar return calls so that we only have one return path rather
than three.
We can almost unify memory returning as well, but it's not quite there.
Signed-off-by: Sean Cross <sean@xobs.io>
Add notes on how to properly hand memory to userspace. This does not yet
work, but is committed here as a work-in-progress.
Signed-off-by: Sean Cross <sean@xobs.io>
When waiting on a thread, it may be the case that the thread we're
joining has exited already. In this case, the correct approach is to
resume execution rather than switching to the parent process.
This fixes an issue where `SWITCHTO_CALLER` is None when joining a
short-lived thread.
Signed-off-by: Sean Cross <sean@xobs.io>
When attempting to return an invalid item, return `DoubleFree`. This is
because such cases are most likely due to instances where a message was
responded to twice.
Signed-off-by: Sean Cross <sean@xobs.io>
Fix a segfault that occurred when using ReplyAndReceiveNext on hosted
mode. This now properly passes memory messages back to the client.
Signed-off-by: Sean Cross <sean@xobs.io>
Implement `ReplyAndReceiveNext` as a syscall. This will reply to a
message, pull the next message out of the queue, and then re-queue the
server to run. This should make servers much more responsive.
This patch has been tested on both hosted and native modes.
Signed-off-by: Sean Cross <sean@xobs.io>