feat(init): spawn service over IPC with per-client allowance refunded on child death; up to 4 death watchers; spawntest on test image
This commit is contained in:
@@ -78,7 +78,7 @@ pub struct Kernel<P: Platform> {
|
||||
/// Where each process's next heap search starts (see memory.rs).
|
||||
heap_cursors: [usize; MAX_PROCESSES],
|
||||
/// Who to signal when each process dies (see syscall/ipc/events.rs).
|
||||
death_watchers: [Option<domain::timer::Target>; MAX_PROCESSES],
|
||||
death_watchers: [[Option<domain::timer::Target>; domain::timer::MAX_WATCHERS]; MAX_PROCESSES],
|
||||
timers: domain::timer::Timers,
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ impl<P: Platform> Kernel<P> {
|
||||
homes: [types::id::CoreId::from_raw(0); MAX_THREADS],
|
||||
tree: domain::capability::tree::CapTree::new(),
|
||||
heap_cursors: [0; MAX_PROCESSES],
|
||||
death_watchers: [None; MAX_PROCESSES],
|
||||
death_watchers: [[None; domain::timer::MAX_WATCHERS]; MAX_PROCESSES],
|
||||
timers: domain::timer::Timers::new(),
|
||||
}
|
||||
}
|
||||
@@ -138,7 +138,8 @@ impl<P: Platform> Kernel<P> {
|
||||
addr_of_mut!((*slot).homes).write([types::id::CoreId::from_raw(0); MAX_THREADS]);
|
||||
addr_of_mut!((*slot).tree).write(domain::capability::tree::CapTree::new());
|
||||
addr_of_mut!((*slot).heap_cursors).write([0; MAX_PROCESSES]);
|
||||
addr_of_mut!((*slot).death_watchers).write([None; MAX_PROCESSES]);
|
||||
addr_of_mut!((*slot).death_watchers)
|
||||
.write([[None; domain::timer::MAX_WATCHERS]; MAX_PROCESSES]);
|
||||
addr_of_mut!((*slot).timers).write(domain::timer::Timers::new());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,22 +40,27 @@ impl<P: Platform> Kernel<P> {
|
||||
_ => return Err(KernelError::WrongObject),
|
||||
};
|
||||
let target = self.target(pid, notification)?;
|
||||
let slot = self
|
||||
let watchers = self
|
||||
.death_watchers
|
||||
.get_mut(watched.raw() as usize)
|
||||
.ok_or(KernelError::InvalidProcess(watched))?;
|
||||
let slot = watchers
|
||||
.iter_mut()
|
||||
.find(|w| w.is_none_or(|w| w == target))
|
||||
.ok_or(KernelError::NoFreeSlot)?;
|
||||
*slot = Some(target);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// A process is dying: tell its watcher, forget its own timer.
|
||||
/// A process is dying: tell its watchers, forget its own timer.
|
||||
pub(crate) fn report_death(&mut self, pid: ProcessId) {
|
||||
self.timers.clear(pid);
|
||||
if let Some(target) = self
|
||||
let watchers = self
|
||||
.death_watchers
|
||||
.get_mut(pid.raw() as usize)
|
||||
.and_then(Option::take)
|
||||
{
|
||||
.map(core::mem::take)
|
||||
.unwrap_or_default();
|
||||
for target in watchers.into_iter().flatten() {
|
||||
self.fire(target);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,3 +161,21 @@ fn notification_id(
|
||||
_ => panic!("not a notification"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn every_watcher_hears_and_there_is_room_for_a_few() {
|
||||
let (mut k, init, proc_cap, first) = watching();
|
||||
let second = k.create_notification_cap(init).unwrap();
|
||||
k.watch_death(init, proc_cap, second).unwrap();
|
||||
// The same notification again takes no new place.
|
||||
k.watch_death(init, proc_cap, second).unwrap();
|
||||
for _ in 2..domain::timer::MAX_WATCHERS {
|
||||
let n = k.create_notification_cap(init).unwrap();
|
||||
k.watch_death(init, proc_cap, n).unwrap();
|
||||
}
|
||||
let extra = k.create_notification_cap(init).unwrap();
|
||||
assert!(k.watch_death(init, proc_cap, extra).is_err());
|
||||
k.handle_syscall(Syscall::Kill { process: proc_cap });
|
||||
assert_eq!(k.poll(init, first).unwrap(), 1);
|
||||
assert_eq!(k.poll(init, second).unwrap(), 1);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user