Skip to content

Commit d652a43

Browse files
committed
test(test_suite): add tests for timeout waits
1 parent 3ce761b commit d652a43

File tree

5 files changed

+205
-6
lines changed

5 files changed

+205
-6
lines changed

src/constance_test_suite/src/kernel_tests/event_group_interrupt.rs

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
//! Interrupts a task waiting for an event bit to be set.
22
//!
3-
//! 1. (`seq`: 0 → 1) `task0` activates `task[1-4]` in a particular order.
4-
//! 2. (`seq`: 1 → 5) `task[1-4]` start waiting for a event bit to be set.
5-
//! 3. (`seq`: 5 → 9) `task0` sets the event bit for four times. `task[1-4]`
6-
//! should be unblocked in the same order.
3+
//! 1. (`seq`: 0 → 1) `task1` starts waiting for an event bit to be set.
4+
//! 2. (`seq`: 1 → 2) `task0` starts running and interrupts `task0`.
5+
//! 3. (`seq`: 2 → 3) `task1` starts waiting for an event bit to be set, this
6+
//! time with a timeout.
7+
//! 4. (`seq`: 3 → 4) `task0` interrupts `task0`.
8+
//! 5. (`seq`: 4 → 5) `task1` completes.
79
//!
810
use constance::{
9-
kernel::{EventGroup, EventGroupWaitFlags, Hunk, QueueOrder, Task, WaitEventGroupError},
11+
kernel::{
12+
EventGroup, EventGroupWaitFlags, Hunk, QueueOrder, Task, WaitEventGroupError,
13+
WaitEventGroupTimeoutError,
14+
},
1015
prelude::*,
16+
time::Duration,
1117
};
1218

1319
use super::Driver;
@@ -36,6 +42,8 @@ impl<System: Kernel> App<System> {
3642
fn task0_body<System: Kernel, D: Driver<App<System>>>(_: usize) {
3743
D::app().seq.expect_and_replace(1, 2);
3844
D::app().task1.interrupt().unwrap();
45+
D::app().seq.expect_and_replace(3, 4);
46+
D::app().task1.interrupt().unwrap();
3947
}
4048

4149
fn task1_body<System: Kernel, D: Driver<App<System>>>(_: usize) {
@@ -48,5 +56,18 @@ fn task1_body<System: Kernel, D: Driver<App<System>>>(_: usize) {
4856
Err(WaitEventGroupError::Interrupted),
4957
);
5058

59+
D::app().seq.expect_and_replace(2, 3);
60+
61+
assert_eq!(
62+
// start waiting, switching to `task0`
63+
D::app()
64+
.eg
65+
.wait_timeout(0b1, EventGroupWaitFlags::CLEAR, Duration::from_millis(100)),
66+
// ... the control is returned when `task0` interrupts `task1`
67+
Err(WaitEventGroupTimeoutError::Interrupted),
68+
);
69+
70+
D::app().seq.expect_and_replace(4, 5);
71+
5172
D::success();
5273
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
//! A task waits for an event bit to be set with timeout.
2+
//!
3+
//! 1. (`seq`: 0 → 1, 0ms) `task1` starts waiting for an event bit to be set.
4+
//! 2. (`seq`: 1 → 2, 0ms) `task0` starts sleeping, which will last for 300
5+
//! milliseconds.
6+
//! 3. (`seq`: 2 → 3, 200ms) `task1` wakes up, seeing that the wait operation
7+
//! timed out. `task1` again starts waiting for the event bit to be set.
8+
//! 4. (`seq`: 3 → 4, 300ms) `task0` wakes up and sets the event bit.
9+
//! 5. (`seq`: 4 → 5, 300ms) `task1` wakes up and preempts `task0`, seeing that
10+
//! the wait operation was successful. Another wait operation will not block
11+
//! because the event bit is already set.
12+
//! 6. (`seq`: 5 → 6, 300ms) `task1` exits.
13+
//! 7. (`seq`: 6 → 7, 300ms) `task0` starts running.
14+
//!
15+
use constance::{
16+
kernel::{EventGroup, EventGroupWaitFlags, Hunk, QueueOrder, Task, WaitEventGroupTimeoutError},
17+
prelude::*,
18+
time::Duration,
19+
};
20+
21+
use super::Driver;
22+
use crate::utils::SeqTracker;
23+
24+
pub struct App<System> {
25+
eg: EventGroup<System>,
26+
seq: Hunk<System, SeqTracker>,
27+
}
28+
29+
impl<System: Kernel> App<System> {
30+
constance::configure! {
31+
pub const fn new<D: Driver<Self>>(_: &mut CfgBuilder<System>) -> Self {
32+
new! { Task<_>, start = task0_body::<System, D>, priority = 2, active = true };
33+
new! { Task<_>, start = task1_body::<System, D>, priority = 1, active = true };
34+
35+
let eg = new! { EventGroup<_>, queue_order = QueueOrder::Fifo };
36+
let seq = new! { Hunk<_, SeqTracker> };
37+
38+
App { eg, seq }
39+
}
40+
}
41+
}
42+
43+
fn task0_body<System: Kernel, D: Driver<App<System>>>(_: usize) {
44+
D::app().seq.expect_and_replace(1, 2);
45+
System::sleep(Duration::from_millis(300)).unwrap();
46+
// `task0` goes into sleep. `task1` wakes up first.
47+
// `task0` follows:
48+
D::app().seq.expect_and_replace(3, 4);
49+
D::app().eg.set(0b1).unwrap();
50+
// preempted by `task1`, which we just woke up
51+
52+
// back from `task1`
53+
D::app().seq.expect_and_replace(6, 7);
54+
D::success();
55+
}
56+
57+
fn task1_body<System: Kernel, D: Driver<App<System>>>(_: usize) {
58+
D::app().seq.expect_and_replace(0, 1);
59+
60+
assert_eq!(
61+
// start waiting, switching to `task0`
62+
D::app().eg.wait_timeout(
63+
0b1,
64+
EventGroupWaitFlags::empty(),
65+
Duration::from_millis(200)
66+
),
67+
// ... the control is returned on timeout
68+
Err(WaitEventGroupTimeoutError::Timeout),
69+
);
70+
71+
D::app().seq.expect_and_replace(2, 3);
72+
73+
// start waiting. wakes up when `task0` sets the event bit
74+
D::app()
75+
.eg
76+
.wait_timeout(
77+
0b1,
78+
EventGroupWaitFlags::empty(),
79+
Duration::from_millis(200),
80+
)
81+
.unwrap();
82+
83+
D::app().seq.expect_and_replace(4, 5);
84+
85+
// this doesn't block because the event bit is already set
86+
D::app()
87+
.eg
88+
.wait_timeout(
89+
0b1,
90+
EventGroupWaitFlags::empty(),
91+
Duration::from_millis(200),
92+
)
93+
.unwrap();
94+
95+
D::app().seq.expect_and_replace(5, 6);
96+
}

src/constance_test_suite/src/kernel_tests/time_misc.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
//! Validates error codes returned by time-related methods. Also, checks
22
//! miscellaneous properties of such methods.
3-
use constance::{kernel::Task, prelude::*, time::Time};
3+
use constance::{
4+
kernel::Task,
5+
prelude::*,
6+
time::{Duration, Time},
7+
};
48

59
use super::Driver;
610

@@ -50,5 +54,20 @@ fn task_body<System: Kernel, D: Driver<App<System>>>(_: usize) {
5054
);
5155
unsafe { System::release_cpu_lock().unwrap() };
5256

57+
// System time should wrap around
58+
let now3 = Time::from_micros(0xfffffffffffe0000);
59+
log::trace!("changing system time to {:?}", now3);
60+
System::set_time(now3).unwrap();
61+
62+
let d = Duration::from_micros(0x40000);
63+
log::trace!("sleeping for {:?}", d);
64+
System::sleep(d).unwrap();
65+
66+
// TODO: `impl Add<Duration> for Time`
67+
let now4 = Time::from_micros(now3.as_micros().wrapping_add(d.as_micros() as _));
68+
let now4_got = System::time().unwrap();
69+
log::trace!("time = {:?} (expected >= {:?})", now4_got, now4);
70+
assert!(now4_got.as_micros() >= now4.as_micros());
71+
5372
D::success();
5473
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//! Launches multiple tasks, each of which calls `sleep` repeatedly.
2+
use constance::{
3+
kernel::{Hunk, Task},
4+
prelude::*,
5+
time::{Duration, Time},
6+
};
7+
use core::sync::atomic::{AtomicUsize, Ordering};
8+
9+
use super::Driver;
10+
11+
pub struct App<System> {
12+
counter: Hunk<System, AtomicUsize>,
13+
}
14+
15+
const TASKS: &[usize] = &[300, 150, 300, 320, 580, 900, 500, 750, 170];
16+
17+
impl<System: Kernel> App<System> {
18+
constance::configure! {
19+
pub const fn new<D: Driver<Self>>(_: &mut CfgBuilder<System>) -> Self {
20+
let mut i = 0;
21+
// FIXME: Work-around for `for` being unsupported in `const fn`
22+
while i < TASKS.len() {
23+
new! { Task<_>,
24+
start = task_body::<System, D>, param = i, priority = 0, active = true };
25+
i += 1;
26+
}
27+
28+
let counter = new! { Hunk<_, AtomicUsize> };
29+
30+
App { counter }
31+
}
32+
}
33+
}
34+
35+
fn task_body<System: Kernel, D: Driver<App<System>>>(i: usize) {
36+
let delay = Duration::from_millis(TASKS[i] as _);
37+
38+
loop {
39+
let now = System::time().unwrap();
40+
log::trace!("[{}] time = {:?}", i, now);
41+
42+
if now.as_secs() >= 2 {
43+
break;
44+
}
45+
46+
System::sleep(delay).unwrap();
47+
48+
let now2 = Time::from_micros(now.as_micros().wrapping_add(delay.as_micros() as _));
49+
let now2_got = System::time().unwrap();
50+
log::trace!("[{}] time = {:?} (expected = {:?})", i, now2_got, now2);
51+
52+
// `now2 <= now2_got < now2 + timing_error`
53+
let delta = now2_got.duration_since(now2);
54+
assert!(!delta.unwrap().is_negative());
55+
assert!(delta.unwrap().as_millis() < 100);
56+
}
57+
58+
if D::app().counter.fetch_add(1, Ordering::Relaxed) == TASKS.len() - 1 {
59+
D::success();
60+
}
61+
}

src/constance_test_suite/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ pub mod kernel_tests {
145145
(mod event_group_order_fifo {}, "event_group_order_fifo"),
146146
(mod event_group_order_task_priority {}, "event_group_order_task_priority"),
147147
(mod event_group_set_and_dispatch {}, "event_group_set_and_dispatch"),
148+
(mod event_group_timeout {}, "event_group_timeout"),
148149
(mod event_group_wait_types {}, "event_group_wait_types"),
149150
(mod interrupt_disallowed_services {}, "interrupt_disallowed_services"),
150151
(mod interrupt_handler_priority {}, "interrupt_handler_priority"),
@@ -162,6 +163,7 @@ pub mod kernel_tests {
162163
(mod task_priority_boost_reset {}, "task_priority_boost_reset"),
163164
(mod task_queue_fifo {}, "task_queue_fifo"),
164165
(mod time_misc {}, "time_misc"),
166+
(mod time_stress {}, "time_stress"),
165167
}
166168

167169
/// Invoke the specified macro with a description of test cases

0 commit comments

Comments
 (0)