refactor(kernel): split ipc/memory/lib/thread by concern; trim comments
This commit is contained in:
@@ -23,6 +23,7 @@ mod memory;
|
||||
pub mod proofs;
|
||||
mod smp;
|
||||
pub mod syscall;
|
||||
mod teardown;
|
||||
|
||||
pub use board::{BoardCaps, BoardDevice};
|
||||
pub use syscall::{SyscallOutcome, SyscallResult};
|
||||
@@ -37,7 +38,7 @@ use domain::{
|
||||
error::KernelError,
|
||||
irq::IrqRoutingTable,
|
||||
memory::{RegionTable, frame::FrameTable, quota::Quota},
|
||||
notification::{MAX_NOTIFICATIONS, NotificationTable},
|
||||
notification::NotificationTable,
|
||||
process::{MAX_PROCESSES, ProcessTable},
|
||||
resource::Resource,
|
||||
scheduler::{Scheduler, multi_core::MultiCoreScheduler},
|
||||
@@ -96,12 +97,10 @@ impl<P: Platform> Kernel<P> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds the kernel directly in `slot`, one table at a time, so the
|
||||
/// whole structure never has to fit on the (small) boot stack.
|
||||
/// Builds the kernel in place, one table at a time, to stay off the boot stack.
|
||||
///
|
||||
/// # Safety
|
||||
/// `slot` must be valid for writes and properly aligned. Any previous
|
||||
/// value is overwritten without being dropped.
|
||||
/// `slot` must be valid for writes and aligned; the old value is overwritten without drop.
|
||||
pub unsafe fn init_in_place(
|
||||
slot: *mut Self,
|
||||
platform: P,
|
||||
@@ -263,123 +262,6 @@ impl<P: Platform> Kernel<P> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn destroy_process(&mut self, pid: ProcessId) {
|
||||
use domain::process::MAX_THREADS_PER_PROCESS;
|
||||
|
||||
let thread_ids: [Option<ThreadId>; MAX_THREADS_PER_PROCESS] = match self.processes.get(pid)
|
||||
{
|
||||
Ok(p) => {
|
||||
let mut ids = [None; MAX_THREADS_PER_PROCESS];
|
||||
for (slot, tid) in ids.iter_mut().zip(p.thread_ids()) {
|
||||
*slot = Some(tid);
|
||||
}
|
||||
ids
|
||||
}
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
self.cleanup_threads(&thread_ids);
|
||||
self.delete_all_caps(pid);
|
||||
self.destroy_endpoints_owned_by(pid);
|
||||
self.destroy_notifications_owned_by(pid);
|
||||
self.teardown_memory(pid);
|
||||
|
||||
let _ = self.processes.destroy(pid);
|
||||
}
|
||||
|
||||
pub(crate) fn cleanup_threads(&mut self, thread_ids: &[Option<ThreadId>]) {
|
||||
use domain::scheduler::Scheduler;
|
||||
for tid in thread_ids.iter().flatten() {
|
||||
self.leave_queue(*tid);
|
||||
if let Some(n) = self
|
||||
.ipc(*tid)
|
||||
.and_then(|s| s.bound)
|
||||
.and_then(|n| self.notifications.get_mut(n))
|
||||
{
|
||||
n.remove_thread(*tid);
|
||||
}
|
||||
let ipc = self.ipc_mut(*tid).map(core::mem::take).unwrap_or_default();
|
||||
if let Some(caller) = ipc.reply_to {
|
||||
self.release_caller(caller);
|
||||
}
|
||||
self.evict(*tid);
|
||||
self.scheduler.remove(*tid);
|
||||
self.set_pending_result(*tid, None);
|
||||
let _ = self.threads.destroy(*tid);
|
||||
}
|
||||
}
|
||||
|
||||
/// Takes a blocked thread off the one queue its block reason names, so
|
||||
/// nothing needs to scan every endpoint and notification.
|
||||
pub(crate) fn leave_queue(&mut self, tid: ThreadId) {
|
||||
use domain::thread::BlockReason::*;
|
||||
let Ok(ThreadState::Blocked(reason)) = self.threads.get(tid).map(|t| *t.state()) else {
|
||||
return;
|
||||
};
|
||||
match reason {
|
||||
Sending(ep) | Calling(ep) => {
|
||||
self.endpoints.get_mut(ep).map(|e| e.remove_sender(tid));
|
||||
}
|
||||
Receiving(ep) => {
|
||||
self.endpoints.get_mut(ep).map(|e| e.remove_receiver(tid));
|
||||
}
|
||||
WaitingNotification(n) => {
|
||||
if let Some(n) = self.notifications.get_mut(n) {
|
||||
n.remove_waiter(tid);
|
||||
}
|
||||
}
|
||||
AwaitingReply => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// Destroys every endpoint `owner` created, waking anyone blocked on
|
||||
/// them with an error instead of leaving them blocked forever.
|
||||
pub(crate) fn destroy_endpoints_owned_by(&mut self, owner: ProcessId) {
|
||||
let mut owned = [None; domain::endpoint::MAX_ENDPOINTS];
|
||||
for (slot, id) in owned.iter_mut().zip(self.endpoints.ids_owned_by(owner)) {
|
||||
*slot = Some(id);
|
||||
}
|
||||
for id in owned.into_iter().flatten() {
|
||||
let Some(mut ep) = self.endpoints.destroy(id) else {
|
||||
continue;
|
||||
};
|
||||
while let Some(tid) = ep.dequeue_sender().or_else(|| ep.dequeue_receiver()) {
|
||||
self.wake_with_error(tid, KernelError::InvalidEndpoint(id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Destroys every notification `owner` created, waking its waiters
|
||||
/// with an error and unbinding its bound thread.
|
||||
pub(crate) fn destroy_notifications_owned_by(&mut self, owner: ProcessId) {
|
||||
let mut owned = [None; MAX_NOTIFICATIONS];
|
||||
for (slot, id) in owned.iter_mut().zip(self.notifications.ids_owned_by(owner)) {
|
||||
*slot = Some(id);
|
||||
}
|
||||
for id in owned.into_iter().flatten() {
|
||||
let Some(mut n) = self.notifications.destroy(id) else {
|
||||
continue;
|
||||
};
|
||||
if let Some(bound) = n.bound()
|
||||
&& let Some(s) = self.ipc_mut(bound)
|
||||
{
|
||||
s.bound = None;
|
||||
}
|
||||
while let Some(tid) = n.pop_waiter() {
|
||||
self.wake_with_error(tid, KernelError::NoSuchObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Makes a blocked thread runnable with `error` as its syscall result,
|
||||
/// dropping whatever it was about to send.
|
||||
fn wake_with_error(&mut self, tid: ThreadId, error: KernelError) {
|
||||
if let Some(s) = self.ipc_mut(tid) {
|
||||
s.outgoing = None;
|
||||
}
|
||||
self.wake(tid, SyscallResult::Error(error));
|
||||
}
|
||||
|
||||
fn check_cap(
|
||||
&self,
|
||||
owner: ProcessId,
|
||||
|
||||
Reference in New Issue
Block a user