sel4_microkit_base/
defer.rs

1//
2// Copyright 2024, Colias Group, LLC
3//
4// SPDX-License-Identifier: BSD-2-Clause
5//
6
7use crate::{Channel, IrqAckError};
8
9// For rustdoc
10#[allow(unused_imports)]
11use crate::Handler;
12
13/// An action deferred for syscall coalescing using [`Handler::take_deferred_action`].
14#[derive(Debug, Copy, Clone, Eq, PartialEq)]
15pub struct DeferredAction {
16    channel: Channel,
17    interface: DeferredActionInterface,
18}
19
20/// A channel interface for which actions can be deferred.
21#[derive(Debug, Copy, Clone, Eq, PartialEq)]
22pub enum DeferredActionInterface {
23    Notify,
24    IrqAck,
25}
26
27impl DeferredAction {
28    pub fn new(channel: Channel, interface: DeferredActionInterface) -> Self {
29        Self { channel, interface }
30    }
31
32    pub fn new_notify(channel: Channel) -> DeferredAction {
33        DeferredAction::new(channel, DeferredActionInterface::Notify)
34    }
35
36    pub fn new_irq_ack(channel: Channel) -> DeferredAction {
37        DeferredAction::new(channel, DeferredActionInterface::IrqAck)
38    }
39
40    pub fn channel(&self) -> Channel {
41        self.channel
42    }
43
44    pub fn interface(&self) -> DeferredActionInterface {
45        self.interface
46    }
47
48    pub fn execute_now(self) -> Result<(), IrqAckError> {
49        match self.interface() {
50            DeferredActionInterface::Notify => {
51                self.channel().notify();
52                Ok(())
53            }
54            DeferredActionInterface::IrqAck => self.channel().irq_ack(),
55        }
56    }
57
58    pub(crate) fn prepare(&self) -> PreparedDeferredAction {
59        match self.interface() {
60            DeferredActionInterface::Notify => PreparedDeferredAction::new(
61                self.channel().notification().cast(),
62                sel4::MessageInfoBuilder::default().build(),
63            ),
64            DeferredActionInterface::IrqAck => PreparedDeferredAction::new(
65                self.channel().irq_handler().cast(),
66                sel4::MessageInfoBuilder::default()
67                    .label(sel4::sys::invocation_label::IRQAckIRQ.into())
68                    .build(),
69            ),
70        }
71    }
72}
73
74#[derive(Debug, Clone, Eq, PartialEq)]
75pub(crate) struct PreparedDeferredAction {
76    cptr: sel4::cap::Unspecified,
77    msg_info: sel4::MessageInfo,
78}
79
80impl PreparedDeferredAction {
81    pub(crate) fn new(cptr: sel4::cap::Unspecified, msg_info: sel4::MessageInfo) -> Self {
82        Self { cptr, msg_info }
83    }
84
85    pub(crate) fn cptr(&self) -> sel4::cap::Unspecified {
86        self.cptr
87    }
88
89    pub(crate) fn msg_info(&self) -> sel4::MessageInfo {
90        self.msg_info.clone() // TODO
91    }
92}
93
94/// Utility type for implementing [`Handler::take_deferred_action`].
95// TODO maybe excessive. remove?
96pub struct DeferredActionSlot {
97    inner: Option<DeferredAction>,
98}
99
100impl DeferredActionSlot {
101    pub const fn new() -> Self {
102        Self { inner: None }
103    }
104
105    pub fn take(&mut self) -> Option<DeferredAction> {
106        self.inner.take()
107    }
108
109    pub fn defer(&mut self, action: DeferredAction) -> Result<(), IrqAckError> {
110        self.inner
111            .replace(action)
112            .map(DeferredAction::execute_now)
113            .unwrap_or(Ok(()))
114    }
115
116    pub fn defer_notify(&mut self, channel: Channel) -> Result<(), IrqAckError> {
117        self.defer(DeferredAction::new_notify(channel))
118    }
119
120    pub fn defer_irq_ack(&mut self, channel: Channel) -> Result<(), IrqAckError> {
121        self.defer(DeferredAction::new_irq_ack(channel))
122    }
123}
124
125impl Default for DeferredActionSlot {
126    fn default() -> Self {
127        Self::new()
128    }
129}