1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
//
// Copyright 2024, Colias Group, LLC
//
// SPDX-License-Identifier: BSD-2-Clause
//

use crate::{Channel, IrqAckError};

// For rustdoc
#[allow(unused_imports)]
use crate::Handler;

/// An action deferred for syscall coalescing using [`Handler::take_deferred_action`].
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct DeferredAction {
    channel: Channel,
    interface: DeferredActionInterface,
}

/// A channel interface for which actions can be deferred.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum DeferredActionInterface {
    Notify,
    IrqAck,
}

impl DeferredAction {
    pub fn new(channel: Channel, interface: DeferredActionInterface) -> Self {
        Self { channel, interface }
    }

    pub fn new_notify(channel: Channel) -> DeferredAction {
        DeferredAction::new(channel, DeferredActionInterface::Notify)
    }

    pub fn new_irq_ack(channel: Channel) -> DeferredAction {
        DeferredAction::new(channel, DeferredActionInterface::IrqAck)
    }

    pub fn channel(&self) -> Channel {
        self.channel
    }

    pub fn interface(&self) -> DeferredActionInterface {
        self.interface
    }

    pub fn execute_now(self) -> Result<(), IrqAckError> {
        match self.interface() {
            DeferredActionInterface::Notify => {
                self.channel().notify();
                Ok(())
            }
            DeferredActionInterface::IrqAck => self.channel().irq_ack(),
        }
    }

    pub(crate) fn prepare(&self) -> PreparedDeferredAction {
        match self.interface() {
            DeferredActionInterface::Notify => PreparedDeferredAction::new(
                self.channel().notification().cast(),
                sel4::MessageInfoBuilder::default().build(),
            ),
            DeferredActionInterface::IrqAck => PreparedDeferredAction::new(
                self.channel().irq_handler().cast(),
                sel4::MessageInfoBuilder::default()
                    .label(sel4::sys::invocation_label::IRQAckIRQ.into())
                    .build(),
            ),
        }
    }
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub(crate) struct PreparedDeferredAction {
    cptr: sel4::cap::Unspecified,
    msg_info: sel4::MessageInfo,
}

impl PreparedDeferredAction {
    pub(crate) fn new(cptr: sel4::cap::Unspecified, msg_info: sel4::MessageInfo) -> Self {
        Self { cptr, msg_info }
    }

    pub(crate) fn cptr(&self) -> sel4::cap::Unspecified {
        self.cptr
    }

    pub(crate) fn msg_info(&self) -> sel4::MessageInfo {
        self.msg_info.clone() // TODO
    }
}

// TODO maybe excessive. remove?
pub struct DeferredActionSlot {
    inner: Option<DeferredAction>,
}

impl DeferredActionSlot {
    pub const fn new() -> Self {
        Self { inner: None }
    }

    pub fn take(&mut self) -> Option<DeferredAction> {
        self.inner.take()
    }

    pub fn defer(&mut self, action: DeferredAction) -> Result<(), IrqAckError> {
        self.inner
            .replace(action)
            .map(DeferredAction::execute_now)
            .unwrap_or(Ok(()))
    }

    pub fn defer_notify(&mut self, channel: Channel) -> Result<(), IrqAckError> {
        self.defer(DeferredAction::new_notify(channel))
    }

    pub fn defer_irq_ack(&mut self, channel: Channel) -> Result<(), IrqAckError> {
        self.defer(DeferredAction::new_irq_ack(channel))
    }
}

impl Default for DeferredActionSlot {
    fn default() -> Self {
        Self::new()
    }
}