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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
use core::marker::PhantomData;

use crate::minimult::Minimult;
use crate::memory::MTRawArray;
use crate::kernel::{MTEvent, MTEventCond};

//

fn wrap_inc(x: usize, bound: usize) -> usize
{
    let y = x + 1;
    if y < bound {y} else {0}
}

//

/// Message queue for task-to-task communication
pub struct MTMsgQueue<'a, M>
{
    mem: MTRawArray<M>,
    wr_idx: usize,
    rd_idx: usize,
    msg_cnt: MTEvent,
    phantom: PhantomData<&'a ()>
}

impl<'a, M> MTMsgQueue<'a, M>
{
    pub(crate) fn new(mem: MTRawArray<M>) -> MTMsgQueue<'a, M> // NOTE: lifetime safety correctness
    {
        MTMsgQueue {
            mem,
            wr_idx: 0,
            rd_idx: 0,
            msg_cnt: MTEvent::new(0),
            phantom: PhantomData
        }
    }

    /// Gets sending and receving channels.
    /// * Returns a tuple of the sender and receiver pair.
    pub fn ch<'q>(&'q mut self) -> (MTMsgSender<'a, 'q, M>, MTMsgReceiver<'a, 'q, M>)
    {
        (
            MTMsgSender {
                q: self,
                phantom: PhantomData
            },
            MTMsgReceiver {
                q: self,
                phantom: PhantomData
            }
        )
    }
}

//

/// Message sending channel
pub struct MTMsgSender<'a, 'q, M>
{
    q: *mut MTMsgQueue<'a, M>,
    phantom: PhantomData<&'q ()>
}

unsafe impl<M: Send> Send for MTMsgSender<'_, '_, M> {}

impl<M> MTMsgSender<'_, '_, M>
{
    /// Gets if there is a vacant message entry.
    /// * Returns the number of vacant message entries.
    pub fn vacant(&self) -> usize
    {
        let q = unsafe { self.q.as_mut().unwrap() };

        q.mem.len() - q.msg_cnt.cnt()
    }

    /// Sends a message.
    /// * `msg` - the message to be sent.
    /// * Blocks if there is no vacant message entry.
    pub fn send(&mut self, msg: M)
    {
        let q = unsafe { self.q.as_mut().unwrap() };

        loop {
            if q.msg_cnt.cnt() < q.mem.len() {
                break;
            }

            Minimult::wait(&q.msg_cnt, MTEventCond::LessThan(q.mem.len()));
        }

        let curr_wr_idx = q.wr_idx;
        let next_wr_idx = wrap_inc(curr_wr_idx, q.mem.len());

        q.mem.write_volatile(curr_wr_idx, msg);

        q.wr_idx = next_wr_idx; // NOTE: volatile access might be necessary

        q.msg_cnt.incr();
        Minimult::signal(&q.msg_cnt);
    }
}

//

/// Message receiving channel
pub struct MTMsgReceiver<'a, 'q, M>
{
    q: *mut MTMsgQueue<'a, M>,
    phantom: PhantomData<&'q ()>
}

unsafe impl<M: Send> Send for MTMsgReceiver<'_, '_, M> {}

impl<M> MTMsgReceiver<'_, '_, M>
{
    /// Gets if there is an available message entry.
    /// * Returns the number of available message entries.
    pub fn available(&self) -> usize
    {
        let q = unsafe { self.q.as_mut().unwrap() };

        q.msg_cnt.cnt()
    }

    /// Receives a message.
    /// * Returns the received message.
    /// * Blocks if there is no available message entry.
    pub fn receive(&mut self) -> M
    {
        let q = unsafe { self.q.as_mut().unwrap() };

        loop {
            if q.msg_cnt.cnt() > 0 {
                break;
            }

            Minimult::wait(&q.msg_cnt, MTEventCond::GreaterThan(0));
        }

        let curr_rd_idx = q.rd_idx;
        let next_rd_idx = wrap_inc(curr_rd_idx, q.mem.len());

        let msg = q.mem.read_volatile(curr_rd_idx);

        q.rd_idx = next_rd_idx; // NOTE: volatile access might be necessary

        q.msg_cnt.decr();
        Minimult::signal(&q.msg_cnt);

        msg
    }
}