Skip to content

Commit 5f2cd34

Browse files
committed
Add NotificationBits type and use it in sys_recv_notification
1 parent 99255fd commit 5f2cd34

5 files changed

Lines changed: 67 additions & 31 deletions

File tree

drv/psc-seq-server/src/main.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -470,9 +470,7 @@ fn main() -> ! {
470470
// Wait for a pin change or timer.
471471
let n = sys_recv_notification(sleep_notifications);
472472
// If the timer bit is set _and the timer has actually fired_...
473-
if n & notifications::TIMER_MASK != 0
474-
&& sys_get_timer().deadline.is_none()
475-
{
473+
if n.check_timer(notifications::TIMER_MASK) {
476474
// Reset our timer forward.
477475
sys_set_timer(
478476
Some(now.saturating_add(POLL_MS)),

drv/stm32h7-sprot-server/src/main.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ impl<S: SpiServer> Io<S> {
389389
.unwrap_lite();
390390

391391
// Determine the deadline after which we'll give up, and start the clock.
392-
let expected_wake = set_timer_relative(max_sleep, TIMER_MASK);
392+
set_timer_relative(max_sleep, TIMER_MASK);
393393

394394
let mut irq_fired = false;
395395
while self.is_rot_irq_asserted() != desired {
@@ -406,21 +406,21 @@ impl<S: SpiServer> Io<S> {
406406
// notification bit, because it's possible *both* notifications were
407407
// posted before we were scheduled again, and if the IRQ did fire,
408408
// we'd prefer to honor that.
409-
irq_fired = notif & ROT_IRQ_MASK != 0
410-
&& self
411-
.sys
409+
irq_fired = notif.check_condition(ROT_IRQ_MASK, || {
410+
self.sys
412411
// If the IRQ hasn't fired, leave it enabled, otherwise,
413412
// if it has fired, don't re-enable the IRQ.
414413
.gpio_irq_control(ROT_IRQ_MASK, IrqControl::Check)
415414
// Sys task shouldn't panic.
416-
.unwrap_lite();
415+
.unwrap_lite()
416+
});
417417
if irq_fired {
418418
break;
419419
}
420420

421421
// If the timer notification was posted, and the GPIO IRQ
422422
// notification wasn't, we've waited for the timeout. Too bad!
423-
if notif & TIMER_MASK != 0 && sys_get_timer().now >= expected_wake {
423+
if notif.check_timer(TIMER_MASK) {
424424
// Disable the IRQ, so that we don't get the notification later
425425
// while in `recv`.
426426
self.sys

drv/stm32xx-i2c/src/lib.rs

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1199,30 +1199,27 @@ fn wfi_raw(event_mask: u32, timeout: I2cTimeout) -> I2cControlResult {
11991199
loop {
12001200
let received = sys_recv_notification(event_mask | TIMER_NOTIFICATION);
12011201

1202-
// If the event arrived _and_ our timer went off, prioritize the event and
1203-
// ignore the timeout.
1204-
if received & event_mask != 0 {
1202+
// If the event arrived _and_ our timer went off, prioritize the event
1203+
// and ignore the timeout.
1204+
if received.check_notification_mask(event_mask) {
12051205
// Attempt to clear our timer. Note that this does not protect against
12061206
// the race where the kernel decided to wake us up, but the timer went
12071207
// off before we got to this point.
12081208
sys_set_timer(None, TIMER_NOTIFICATION);
12091209
break I2cControlResult::Interrupted;
1210-
} else {
1211-
// The timer bit must have been set. Verify that our timer has
1212-
// actually expired:
1213-
if sys_get_timer().now >= dead {
1214-
break I2cControlResult::TimedOut;
1215-
}
1216-
1217-
// Otherwise, one of two things has happened:
1218-
// 1. Some joker has posted to our timer bit. Ha ha very funny.
1219-
// 2. The timer bit was _already set_ on entry to this routine, as a
1220-
// hangover from a previous run.
1221-
//
1222-
// We don't need to re-set our timer here because we sampled
1223-
// sys_get_timer _after_ receiving notifications, meaning it either
1224-
// hasn't gone off, or it has gone off but that fact is still stored
1225-
// in our notification bits.
1210+
} else if received.check_timer(TIMER_NOTIFICATION) {
1211+
// The timer has actually expired!
1212+
break I2cControlResult::TimedOut;
12261213
}
1214+
1215+
// Otherwise, one of two things has happened:
1216+
// 1. Some joker has posted to our timer bit. Ha ha very funny.
1217+
// 2. The timer bit was _already set_ on entry to this routine, as a
1218+
// hangover from a previous run.
1219+
//
1220+
// We don't need to re-set our timer here because we sampled
1221+
// sys_get_timer _after_ receiving notifications, meaning it either
1222+
// hasn't gone off, or it has gone off but that fact is still stored in
1223+
// our notification bits.
12271224
}
12281225
}

sys/userlib/src/lib.rs

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -330,16 +330,57 @@ pub fn sys_recv(
330330
}
331331
}
332332

333+
#[derive(Copy, Clone, PartialEq, Eq)]
334+
pub struct NotificationBits(u32);
335+
336+
impl NotificationBits {
337+
/// Wraps a `u32`
338+
#[inline]
339+
pub fn new(bits: u32) -> Self {
340+
Self(bits)
341+
}
342+
343+
/// Returns the raw notification bitmask
344+
#[inline]
345+
pub fn get_raw_bits(&self) -> u32 {
346+
self.0
347+
}
348+
349+
/// Checks whether the given mask is active, along with `cond` being true
350+
#[inline]
351+
pub fn check_condition<F: Fn() -> bool>(&self, mask: u32, cond: F) -> bool {
352+
self.check_notification_mask(mask) != 0 && cond()
353+
}
354+
355+
/// Checks whether the given notification mask is active
356+
///
357+
/// Notifications may occur spuriously; it is recommended to use
358+
/// `check_condition` instead, if there's a way to confirm that the event
359+
/// has actually occurred.
360+
#[inline]
361+
pub fn check_notification_mask(&self, mask: u32) -> bool {
362+
(self.0 & mask) != 0
363+
}
364+
365+
/// Checks whether a timer notification has expired
366+
///
367+
/// `mask` must the notification bitmask for the timer notification
368+
#[inline]
369+
pub fn check_timer(&self, timer_mask: u32) -> bool {
370+
self.check_condition(timer_mask, || sys_get_timer().deadline.is_none())
371+
}
372+
}
373+
333374
/// Convenience wrapper for `sys_recv` for the specific, but common, task of
334375
/// listening for notifications. In this specific use, it has the advantage of
335376
/// never panicking and not returning a `Result` that must be checked.
336377
#[inline(always)]
337-
pub fn sys_recv_notification(notification_mask: u32) -> u32 {
378+
pub fn sys_recv_notification(notification_mask: u32) -> NotificationBits {
338379
match sys_recv(&mut [], notification_mask, Some(TaskId::KERNEL)) {
339380
Ok(rm) => {
340381
// The notification bits come back from the kernel in the operation
341382
// code field.
342-
rm.operation
383+
NotificationBits(rm.operation)
343384
}
344385
Err(_) => {
345386
// Safety: Because we passed Some(TaskId::KERNEL), this is defined

task/nucleo-user-button/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ enum Trace {
5353
},
5454

5555
/// We received a notification with these bits set.
56-
Notification(u32),
56+
Notification(userlib::NotificationBits),
5757

5858
/// We called the `UserLeds.led_toggle` IPC.
5959
LedToggle { led: usize },

0 commit comments

Comments
 (0)