feat(kernel): add WaitForInterrupt, AcknowledgeInterrupt, and WaitAny syscalls
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
use super::*;
|
||||
use crate::{SyscallOutcome, SyscallResult};
|
||||
use domain::message::Message;
|
||||
use domain::syscall::Syscall;
|
||||
use domain::syscall::{Syscall, WaitSet, WakeReason};
|
||||
use domain::thread::BlockReason;
|
||||
use types::bounded::CapSlot;
|
||||
use types::id::ThreadId;
|
||||
use types::id::{IrqId, ThreadId};
|
||||
use types::permission::{Permission, PermissionSet};
|
||||
|
||||
fn setup_ipc_kernel() -> (
|
||||
@@ -138,3 +138,96 @@ fn send_checks_endpoint_capability() {
|
||||
SyscallOutcome::Complete(SyscallResult::Error(_))
|
||||
));
|
||||
}
|
||||
|
||||
// --- WaitForInterrupt / AcknowledgeInterrupt ---
|
||||
|
||||
#[test]
|
||||
fn wait_for_interrupt_blocks_caller() {
|
||||
let (mut k, pid_a, _, _, _, _) = setup_ipc_kernel();
|
||||
let irq = IrqId::from_raw(7);
|
||||
let irq_slot = k.grant_cap_for_test(
|
||||
pid_a,
|
||||
domain::resource::Resource::Interrupt(irq),
|
||||
PermissionSet::empty()
|
||||
.with(Permission::Read)
|
||||
.with(Permission::Write),
|
||||
);
|
||||
|
||||
let outcome = k.handle_syscall(Syscall::WaitForInterrupt { irq: irq_slot });
|
||||
assert!(matches!(
|
||||
outcome,
|
||||
SyscallOutcome::BlockCaller(BlockReason::WaitingForInterrupt(_))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ack_interrupt_returns_ok() {
|
||||
let (mut k, pid_a, _, _, _, _) = setup_ipc_kernel();
|
||||
let irq = IrqId::from_raw(7);
|
||||
let irq_slot = k.grant_cap_for_test(
|
||||
pid_a,
|
||||
domain::resource::Resource::Interrupt(irq),
|
||||
PermissionSet::empty().with(Permission::Write),
|
||||
);
|
||||
|
||||
let outcome = k.handle_syscall(Syscall::AcknowledgeInterrupt { irq: irq_slot });
|
||||
assert!(matches!(
|
||||
outcome,
|
||||
SyscallOutcome::Complete(SyscallResult::Ok)
|
||||
));
|
||||
}
|
||||
|
||||
// --- WaitAny ---
|
||||
|
||||
#[test]
|
||||
fn wait_any_with_ready_source_returns_immediately() {
|
||||
let (mut k, pid_a, _, cap_a, cap_b, tid_b) = setup_ipc_kernel();
|
||||
let tid_a = ThreadId::from_raw(0);
|
||||
|
||||
// Thread B sends a message (blocks since no receiver)
|
||||
k.switch_to_thread_for_test(tid_b);
|
||||
k.handle_syscall(Syscall::Send {
|
||||
endpoint: cap_b,
|
||||
message: Message::from_words([77, 0, 0, 0]),
|
||||
});
|
||||
|
||||
// Thread A does WaitAny on the endpoint
|
||||
k.switch_to_thread_for_test(tid_a);
|
||||
let wait_set = WaitSet::new(
|
||||
[Some(cap_a), None, None, None],
|
||||
[None, None, None, None],
|
||||
);
|
||||
let outcome = k.handle_syscall(Syscall::WaitAny { sources: wait_set });
|
||||
assert!(matches!(
|
||||
outcome,
|
||||
SyscallOutcome::Complete(SyscallResult::WakeReason(WakeReason::MessageReady(_)))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wait_any_with_no_ready_source_blocks() {
|
||||
let (mut k, pid_a, _, cap_a, _, _) = setup_ipc_kernel();
|
||||
let wait_set = WaitSet::new(
|
||||
[Some(cap_a), None, None, None],
|
||||
[None, None, None, None],
|
||||
);
|
||||
let outcome = k.handle_syscall(Syscall::WaitAny { sources: wait_set });
|
||||
assert!(matches!(
|
||||
outcome,
|
||||
SyscallOutcome::BlockCaller(BlockReason::WaitingAny)
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wait_any_empty_sources_returns_error() {
|
||||
let (mut k, _, _, _, _, _) = setup_ipc_kernel();
|
||||
let wait_set = WaitSet::new(
|
||||
[None, None, None, None],
|
||||
[None, None, None, None],
|
||||
);
|
||||
let outcome = k.handle_syscall(Syscall::WaitAny { sources: wait_set });
|
||||
assert!(matches!(
|
||||
outcome,
|
||||
SyscallOutcome::Complete(SyscallResult::Error(_))
|
||||
));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user