Skip to content

Commit e970838

Browse files
committed
feat(port_std): support true asynchronous interrupts
1 parent e4d1696 commit e970838

File tree

4 files changed

+110
-3
lines changed

4 files changed

+110
-3
lines changed

src/constance_port_std/src/lib.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,4 @@ Based on the internal user-mode scheduling (UMS) framework, we treat interrupt h
5656

5757
The interrupt line [`INTERRUPT_LINE_DISPATCH`] is reserved for the dispatcher.
5858

59-
**To be implemented:** True asynchronous interrupts aren't supported yet.
60-
6159
[`INTERRUPT_LINE_DISPATCH`]: crate::INTERRUPT_LINE_DISPATCH

src/constance_port_std/src/lib.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,32 @@ pub fn shutdown<System: PortInstance>() {
546546
.shutdown();
547547
}
548548

549+
/// Pend an interrupt line from an external thread.
550+
///
551+
/// It's illegal to call this method from a thread managed by the port (i.e.,
552+
/// you can't call it from a task or an interrupt handler). Use
553+
/// [`constance::kernel::InterruptLine::pend`] instead in such cases.
554+
pub fn pend_interrupt_line<System: PortInstance>(
555+
num: InterruptNum,
556+
) -> Result<(), PendInterruptLineError> {
557+
log::trace!("external-pend_interrupt_line{:?}", (num,));
558+
559+
assert_eq!(THREAD_ROLE.with(|r| r.get()), ThreadRole::Unknown);
560+
561+
let state = System::port_state();
562+
let mut lock = state.thread_group.get().unwrap().lock();
563+
lock.scheduler()
564+
.update_line(num, |line| line.pended = true)
565+
.map_err(|sched::BadIntLineError| PendInterruptLineError::BadParam)?;
566+
567+
if sched::check_preemption_by_interrupt(state.thread_group.get().unwrap(), &mut lock) {
568+
lock.preempt();
569+
drop(lock);
570+
}
571+
572+
Ok(())
573+
}
574+
549575
#[macro_export]
550576
macro_rules! use_port {
551577
(unsafe $vis:vis struct $sys:ident) => {
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
//! Pends an interrupt from an external thread.
2+
use constance::{
3+
kernel::{Hunk, InterruptHandler, InterruptLine, Task},
4+
prelude::*,
5+
};
6+
use constance_test_suite::kernel_tests::Driver;
7+
use std::{
8+
sync::atomic::{AtomicBool, Ordering},
9+
thread::{sleep, spawn},
10+
time::Duration,
11+
};
12+
13+
use constance_port_std::PortInstance;
14+
15+
pub struct App<System> {
16+
int: Option<InterruptLine<System>>,
17+
done: Hunk<System, AtomicBool>,
18+
}
19+
20+
impl<System: PortInstance> App<System> {
21+
constance::configure! {
22+
pub const fn new<D: Driver<Self>>(_: &mut CfgBuilder<System>) -> Self {
23+
new! { Task<_>, start = task_body1::<System, D>, priority = 1, active = true };
24+
25+
let int = if let [int_line, ..] = *D::INTERRUPT_LINES {
26+
new! { InterruptHandler<_>,
27+
line = int_line, start = isr::<System, D>};
28+
29+
Some(new! { InterruptLine<_>,
30+
line = int_line, priority = D::INTERRUPT_PRIORITY_LOW , enabled = true })
31+
} else {
32+
None
33+
};
34+
35+
let done = new! { Hunk<_, AtomicBool> };
36+
37+
App { int, done }
38+
}
39+
}
40+
}
41+
42+
fn task_body1<System: PortInstance, D: Driver<App<System>>>(_: usize) {
43+
let int = if let Some(int) = D::app().int {
44+
int
45+
} else {
46+
log::warn!("No interrupt lines defined, skipping the test");
47+
D::success();
48+
return;
49+
};
50+
51+
// Spawn a host thread
52+
log::debug!("spawning an external thread");
53+
spawn(move || {
54+
sleep(Duration::from_millis(100));
55+
log::debug!("pending {:?}", int);
56+
constance_port_std::pend_interrupt_line::<System>(int.num()).unwrap();
57+
});
58+
59+
log::debug!("waiting for `done` to be set...");
60+
while !D::app().done.load(Ordering::Relaxed) {}
61+
log::debug!("success!");
62+
63+
D::success();
64+
}
65+
66+
fn isr<System: Kernel, D: Driver<App<System>>>(_: usize) {
67+
D::app().done.store(true, Ordering::Relaxed);
68+
}

src/constance_port_std/tests/test_suite.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#![feature(const_if_match)]
44
#![feature(never_type)]
55
#![feature(const_mut_refs)]
6+
#![feature(const_fn)]
67

78
use constance_port_std::PortInstance;
89
use std::sync::atomic::{AtomicBool, Ordering};
@@ -42,8 +43,22 @@ impl KernelTestUtil {
4243
}
4344
}
4445

46+
mod kernel_tests {
47+
pub mod external_interrupt;
48+
}
49+
4550
macro_rules! instantiate_kernel_tests {
46-
($(
51+
( $( { $($tt:tt)* }, )* ) => {
52+
instantiate_kernel_tests!(
53+
@inner
54+
55+
$( { $($tt)* }, )*
56+
57+
// Port-specific tests
58+
{ path: crate::kernel_tests::external_interrupt, name_ident: external_interrupt, },
59+
);
60+
};
61+
( @inner $(
4762
{ path: $path:path, name_ident: $name_ident:ident, $($rest:tt)* },
4863
)*) => {$(
4964
mod $name_ident {

0 commit comments

Comments
 (0)