Skip to content

Commit b0cc370

Browse files
committed
Add NotificationBits type and use it in sys_recv_notification
1 parent e199470 commit b0cc370

4 files changed

Lines changed: 66 additions & 12 deletions

File tree

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -720,9 +720,7 @@ fn main() -> ! {
720720
// Wait for a pin change or timer.
721721
let n = sys_recv_notification(sleep_notifications);
722722
// If the timer bit is set _and the timer has actually fired_...
723-
if n & notifications::TIMER_MASK != 0
724-
&& sys_get_timer().deadline.is_none()
725-
{
723+
if n.has_timer_fired(notifications::TIMER_MASK) {
726724
// Reset our timer forward.
727725
sys_set_timer(
728726
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

sys/userlib/src/lib.rs

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

333+
/// Bitmask representing notifications from the kernel
334+
///
335+
/// The raw notification bits are available in [`get_raw_bits`], but
336+
/// higher-level functions make it harder to misuse notifications.
337+
#[derive(Copy, Clone)]
338+
#[repr(transparent)]
339+
pub struct NotificationBits(u32);
340+
341+
impl NotificationBits {
342+
/// Wraps a `u32`
343+
#[inline]
344+
pub fn new(bits: u32) -> Self {
345+
Self(bits)
346+
}
347+
348+
/// Returns the raw notification bitmask
349+
#[inline]
350+
pub fn get_raw_bits(&self) -> u32 {
351+
self.0
352+
}
353+
354+
/// Checks if a condition signaled by notification bits holds
355+
///
356+
/// The `cond` function should verify the underlying condition, but as an
357+
/// optimization, it will only be called if any bits set in mask are also
358+
/// set in `self`. This double-check is important, because notification bits
359+
/// can potentially be set even if the underlying condition is not true,
360+
/// such as with extra pended interrupts or inter-task use of `sys_post`.
361+
///
362+
/// If you find yourself passing `|| true` here, see
363+
/// [`check_notification_mask`].
364+
#[inline]
365+
pub fn check_condition<F: Fn() -> bool>(&self, mask: u32, cond: F) -> bool {
366+
self.check_notification_mask(mask) && cond()
367+
}
368+
369+
/// Checks whether the given notification mask is active
370+
///
371+
/// Notifications may occur spuriously; it is recommended to use
372+
/// `check_condition` instead, if there's a way to verify that the event has
373+
/// actually occurred.
374+
#[inline]
375+
pub fn check_notification_mask(&self, mask: u32) -> bool {
376+
(self.0 & mask) != 0
377+
}
378+
379+
/// Checks whether a timer appears to have gone off, because the timer_mask
380+
/// bit is set and the kernel timer is no longer set.
381+
///
382+
/// `mask` must the notification bitmask for the timer notification
383+
#[inline]
384+
pub fn has_timer_fired(&self, timer_mask: u32) -> bool {
385+
self.check_condition(timer_mask, || sys_get_timer().deadline.is_none())
386+
}
387+
}
388+
333389
/// Convenience wrapper for `sys_recv` for the specific, but common, task of
334390
/// listening for notifications. In this specific use, it has the advantage of
335391
/// never panicking and not returning a `Result` that must be checked.
336392
#[inline(always)]
337-
pub fn sys_recv_notification(notification_mask: u32) -> u32 {
393+
pub fn sys_recv_notification(notification_mask: u32) -> NotificationBits {
338394
match sys_recv(&mut [], notification_mask, Some(TaskId::KERNEL)) {
339395
Ok(rm) => {
340396
// The notification bits come back from the kernel in the operation
341397
// code field.
342-
rm.operation
398+
NotificationBits(rm.operation)
343399
}
344400
Err(_) => {
345401
// 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)