Skip to content

Commit 737af5f

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

5 files changed

Lines changed: 69 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.has_timer_fired(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.has_timer_fired(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.has_timer_fired(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: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -330,16 +330,59 @@ pub fn sys_recv(
330330
}
331331
}
332332

333+
/// Bitmask representing notifications from the kernel
334+
#[derive(Copy, Clone)]
335+
#[repr(transparent)]
336+
pub struct NotificationBits(u32);
337+
338+
impl NotificationBits {
339+
/// Wraps a `u32`
340+
#[inline]
341+
pub fn new(bits: u32) -> Self {
342+
Self(bits)
343+
}
344+
345+
/// Returns the raw notification bitmask
346+
#[inline]
347+
pub fn get_raw_bits(&self) -> u32 {
348+
self.0
349+
}
350+
351+
/// Checks whether the given mask is active, along with `cond` being true
352+
#[inline]
353+
pub fn check_condition<F: Fn() -> bool>(&self, mask: u32, cond: F) -> bool {
354+
self.check_notification_mask(mask) && cond()
355+
}
356+
357+
/// Checks whether the given notification mask is active
358+
///
359+
/// Notifications may occur spuriously; it is recommended to use
360+
/// `check_condition` instead, if there's a way to confirm that the event
361+
/// has actually occurred.
362+
#[inline]
363+
pub fn check_notification_mask(&self, mask: u32) -> bool {
364+
(self.0 & mask) != 0
365+
}
366+
367+
/// Checks whether a timer notification has expired
368+
///
369+
/// `mask` must the notification bitmask for the timer notification
370+
#[inline]
371+
pub fn has_timer_fired(&self, timer_mask: u32) -> bool {
372+
self.check_condition(timer_mask, || sys_get_timer().deadline.is_none())
373+
}
374+
}
375+
333376
/// Convenience wrapper for `sys_recv` for the specific, but common, task of
334377
/// listening for notifications. In this specific use, it has the advantage of
335378
/// never panicking and not returning a `Result` that must be checked.
336379
#[inline(always)]
337-
pub fn sys_recv_notification(notification_mask: u32) -> u32 {
380+
pub fn sys_recv_notification(notification_mask: u32) -> NotificationBits {
338381
match sys_recv(&mut [], notification_mask, Some(TaskId::KERNEL)) {
339382
Ok(rm) => {
340383
// The notification bits come back from the kernel in the operation
341384
// code field.
342-
rm.operation
385+
NotificationBits(rm.operation)
343386
}
344387
Err(_) => {
345388
// 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
@@ -104,7 +104,7 @@ pub fn main() -> ! {
104104

105105
// Wait for the user button to be pressed.
106106
let notif = sys_recv_notification(notifications::BUTTON_MASK);
107-
ringbuf_entry!(Trace::Notification(notif));
107+
ringbuf_entry!(Trace::Notification(notif.get_raw_bits()));
108108
}
109109
}
110110

0 commit comments

Comments
 (0)