minimult_cortex_m/
shared.rs

1use core::marker::PhantomData;
2
3use crate::minimult::Minimult;
4use crate::kernel::{MTEvent, MTEventCond};
5use crate::bkptpanic::BKUnwrap;
6
7/// Shared variable among tasks
8pub struct MTShared<'a, M>
9{
10    holder: M,
11    rw_cnt: MTEvent,
12    phantom: PhantomData<&'a ()>
13}
14
15impl<'a, M> MTShared<'a, M>
16{
17    pub(crate) fn new(holder: M) -> MTShared<'a, M> // NOTE: lifetime safety correctness
18    {
19        MTShared {
20            holder,
21            rw_cnt: MTEvent::new(1),
22            phantom: PhantomData
23        }
24    }
25
26    /// Gets a shared variable access channel.
27    /// * Returns the shared access channel.
28    pub fn ch<'s>(&'s self) -> MTSharedCh<'a, 's, M>
29    {
30        MTSharedCh {
31            s: (self as *const Self) as *mut Self, // NOTE: mutability conversion
32            phantom: PhantomData
33        }
34    }
35}
36
37//
38
39/// Shared variable access channel
40pub struct MTSharedCh<'a, 's, M>
41{
42    s: *mut MTShared<'a, M>,
43    phantom: PhantomData<&'s ()>
44}
45
46unsafe impl<M: Send> Send for MTSharedCh<'_, '_, M> {}
47
48impl<M> MTSharedCh<'_, '_, M>
49{
50    /// Makes an immutable access to a shared variable.
51    /// * Returns a `Deref`-able wrapper of the shared variable.
52    /// * Blocks if the shared variable is `touch`ed by other channels.
53    pub fn look<'c>(&'c self) -> MTSharedLook<'c, M>
54    {
55        loop {
56            if let Some(v) = self.try_look() {
57                return v;
58            }
59            else {
60                let s = unsafe { self.s.as_mut().bk_unwrap() };
61                Minimult::wait(&s.rw_cnt, MTEventCond::GreaterThan(0));
62            }
63        }
64    }
65
66    /// Tries to make an immutable access to a shared variable.
67    /// * Returns a `Deref`-able wrapper of the shared variable in `Option`.
68    /// * Gets `None` if the shared variable is `touch`ed by other channels.
69    pub fn try_look<'c>(&'c self) -> Option<MTSharedLook<'c, M>>
70    {
71        let s = unsafe { self.s.as_mut().bk_unwrap() };
72
73        if s.rw_cnt.incr_ifgt0() {
74            Some(MTSharedLook {
75                holder: &s.holder,
76                rw_cnt: &mut s.rw_cnt
77            })
78        }
79        else {
80            None
81        }
82    }
83
84    /// Makes a mutable access to a shared variable.
85    /// * Returns a `DerefMut`-able wrapper of the shared variable.
86    /// * Blocks if the shared variable is `look`ed or `touch`ed by other channels.
87    pub fn touch<'c>(&'c self) -> MTSharedTouch<'c, M>
88    {
89        loop {
90            if let Some(v) = self.try_touch() {
91                return v;
92            }
93            else {
94                let s = unsafe { self.s.as_mut().bk_unwrap() };
95                Minimult::wait(&s.rw_cnt, MTEventCond::Equal(1));
96            }
97        }
98    }
99
100    /// Tries to make a mutable access to a shared variable.
101    /// * Returns a `DerefMut`-able wrapper of the shared variable in `Option`.
102    /// * Gets `None` if the shared variable is `look`ed or `touch`ed by other channels.
103    pub fn try_touch<'c>(&'c self) -> Option<MTSharedTouch<'c, M>>
104    {
105        let s = unsafe { self.s.as_mut().bk_unwrap() };
106
107        if s.rw_cnt.decr_if1() {
108            Some(MTSharedTouch {
109                holder: &mut s.holder,
110                rw_cnt: &mut s.rw_cnt
111            })
112        }
113        else {
114            None
115        }
116    }
117}
118
119//
120
121/// Shared variable's immutable access scope wrapper
122pub struct MTSharedLook<'c, M>
123{
124    holder: &'c M,
125    rw_cnt: &'c mut MTEvent,
126}
127
128impl<M> core::ops::Deref for MTSharedLook<'_, M>
129{
130    type Target = M;
131
132    fn deref(&self) -> &Self::Target
133    {
134        self.holder
135    }
136}
137
138impl<M> Drop for MTSharedLook<'_, M>
139{
140    fn drop(&mut self)
141    {
142        self.rw_cnt.decr();
143        Minimult::signal(&self.rw_cnt);
144    }
145}
146
147//
148
149/// Shared variable's mutable access scope wrapper
150pub struct MTSharedTouch<'c, M>
151{
152    holder: &'c mut M,
153    rw_cnt: &'c mut MTEvent,
154}
155
156impl<M> core::ops::Deref for MTSharedTouch<'_, M>
157{
158    type Target = M;
159
160    fn deref(&self) -> &Self::Target
161    {
162        self.holder
163    }
164}
165
166impl<M> core::ops::DerefMut for MTSharedTouch<'_, M>
167{
168    fn deref_mut(&mut self) -> &mut Self::Target
169    {
170        self.holder
171    }
172}
173
174impl<M> Drop for MTSharedTouch<'_, M>
175{
176    fn drop(&mut self)
177    {
178        self.rw_cnt.incr();
179        Minimult::signal(&self.rw_cnt);
180    }
181}