riot_rs_runqueue/
runqueue.rs1use core::mem;
2
3use self::clist::CList;
4
5const USIZE_BITS: usize = mem::size_of::<usize>() * 8;
6
7pub type RunqueueId = u8;
8pub type ThreadId = u8;
9
10pub struct RunQueue<const N_QUEUES: usize, const N_THREADS: usize> {
24 bitcache: usize,
25 queues: clist::CList<N_QUEUES, N_THREADS>,
26}
27
28impl<const N_QUEUES: usize, const N_THREADS: usize> RunQueue<{ N_QUEUES }, { N_THREADS }> {
29 pub const fn new() -> RunQueue<{ N_QUEUES }, { N_THREADS }> {
30 RunQueue {
33 bitcache: 0,
34 queues: CList::new(),
35 }
36 }
37
38 pub fn add(&mut self, n: ThreadId, rq: RunqueueId) {
40 debug_assert!((n as usize) < N_THREADS);
41 debug_assert!((rq as usize) < N_QUEUES);
42 self.bitcache |= 1 << rq;
43 self.queues.push(n, rq);
44 }
45
46 pub fn del(&mut self, n: ThreadId, rq: RunqueueId) {
50 debug_assert!((n as usize) < N_THREADS);
51 debug_assert!((rq as usize) < N_QUEUES);
52 let popped = self.queues.pop_head(rq);
53 assert_eq!(popped, Some(n as u8));
55 if self.queues.is_empty(rq) {
56 self.bitcache &= !(1 << rq);
57 }
58 }
59
60 fn ffs(val: usize) -> u32 {
61 USIZE_BITS as u32 - val.leading_zeros()
62 }
63
64 pub fn get_next(&self) -> Option<u8> {
68 let rq_ffs = Self::ffs(self.bitcache);
69 if rq_ffs > 0 {
70 let rq = (rq_ffs - 1) as RunqueueId;
71 self.queues.peek_head(rq)
72 } else {
73 None
74 }
75 }
76
77 pub fn advance(&mut self, rq: RunqueueId) {
80 debug_assert!((rq as usize) < N_QUEUES);
81 self.queues.advance(rq)
82 }
83}
84
85mod clist {
86 use super::{RunqueueId, ThreadId};
91
92 #[derive(Debug, Copy, Clone)]
93 pub struct CList<const N_QUEUES: usize, const N_THREADS: usize> {
94 tail: [u8; N_QUEUES],
95 next_idxs: [u8; N_THREADS],
96 }
97
98 impl<const N_QUEUES: usize, const N_THREADS: usize> CList<N_QUEUES, N_THREADS> {
99 pub const fn new() -> Self {
100 CList {
103 tail: [Self::sentinel(); N_QUEUES],
104 next_idxs: [Self::sentinel(); N_THREADS],
105 }
106 }
107
108 pub const fn sentinel() -> u8 {
109 0xFF
110 }
111
112 pub fn is_empty(&self, rq: RunqueueId) -> bool {
113 self.tail[rq as usize] == Self::sentinel()
114 }
115
116 pub fn push(&mut self, n: ThreadId, rq: RunqueueId) {
117 assert!(n < Self::sentinel());
118 if self.next_idxs[n as usize] == Self::sentinel() {
119 if self.tail[rq as usize] == Self::sentinel() {
120 self.tail[rq as usize] = n;
122 self.next_idxs[n as usize] = n;
123 } else {
124 self.next_idxs[n as usize] = self.next_idxs[self.tail[rq as usize] as usize];
127 self.next_idxs[self.tail[rq as usize] as usize] = n;
129 self.tail[rq as usize] = n;
131 }
132 }
133 }
134
135 pub fn pop_head(&mut self, rq: RunqueueId) -> Option<u8> {
136 if self.tail[rq as usize] == Self::sentinel() {
137 None
139 } else {
140 let head = self.next_idxs[self.tail[rq as usize] as usize];
141 if head == self.tail[rq as usize] {
142 self.tail[rq as usize] = Self::sentinel();
145 } else {
147 self.next_idxs[self.tail[rq as usize] as usize] = self.next_idxs[head as usize];
150 }
151
152 self.next_idxs[head as usize] = Self::sentinel();
154 Some(head)
155 }
156 }
157
158 pub fn peek_head(&self, rq: RunqueueId) -> Option<u8> {
159 if self.tail[rq as usize] == Self::sentinel() {
160 None
161 } else {
162 Some(self.next_idxs[self.tail[rq as usize] as usize])
163 }
164 }
165
166 pub fn advance(&mut self, rq: RunqueueId) {
167 if self.tail[rq as usize] != Self::sentinel() {
168 self.tail[rq as usize] = self.next_idxs[self.tail[rq as usize] as usize];
169 }
170 }
171 }
172
173 #[cfg(test)]
174 mod tests {
175 use super::*;
176
177 #[test]
178 fn test_clist_basic() {
179 let mut clist: CList<8, 32> = CList::new();
180 assert!(clist.is_empty(0));
181 clist.push(0, 0);
182 assert_eq!(clist.pop_head(0), Some(0));
183 assert_eq!(clist.pop_head(0), None);
184 }
185
186 #[test]
187 fn test_clist_push_already_in_list() {
188 let mut clist: CList<8, 32> = CList::new();
189 assert!(clist.is_empty(0));
190 clist.push(0, 0);
191 clist.push(0, 0);
192 assert_eq!(clist.pop_head(0), Some(0));
193 assert_eq!(clist.pop_head(0), None);
194 assert!(clist.is_empty(0));
195 }
196
197 #[test]
198 fn test_clist_push_two() {
199 let mut clist: CList<8, 32> = CList::new();
200 assert!(clist.is_empty(0));
201 clist.push(0, 0);
202 clist.push(1, 0);
203 assert_eq!(clist.pop_head(0), Some(0));
204 assert_eq!(clist.pop_head(0), Some(1));
205 assert_eq!(clist.pop_head(0), None);
206 assert!(clist.is_empty(0));
207 }
208
209 #[test]
210 fn test_clist_push_all() {
211 const N: usize = 255;
212 let mut clist: CList<8, N> = CList::new();
213 assert!(clist.is_empty(0));
214 for i in 0..(N - 1) {
215 println!("pushing {}", i);
216 clist.push(i as u8, 0);
217 }
218 for i in 0..(N - 1) {
219 println!("{}", i);
220 assert_eq!(clist.pop_head(0), Some(i as u8));
221 }
222 assert_eq!(clist.pop_head(0), None);
223 assert!(clist.is_empty(0));
224 }
225
226 #[test]
227 fn test_clist_advance() {
228 let mut clist: CList<8, 32> = CList::new();
229 assert!(clist.is_empty(0));
230 clist.push(0, 0);
231 clist.push(1, 0);
232 clist.advance(0);
233 assert_eq!(clist.pop_head(0), Some(1));
234 assert_eq!(clist.pop_head(0), Some(0));
235 assert_eq!(clist.pop_head(0), None);
236 assert!(clist.is_empty(0));
237 }
238
239 #[test]
240 fn test_clist_peek_head() {
241 let mut clist: CList<8, 32> = CList::new();
242 assert!(clist.is_empty(0));
243 clist.push(0, 0);
244 clist.push(1, 0);
245 assert_eq!(clist.peek_head(0), Some(0));
246 assert_eq!(clist.peek_head(0), Some(0));
247 assert_eq!(clist.pop_head(0), Some(0));
248 assert_eq!(clist.peek_head(0), Some(1));
249 assert_eq!(clist.pop_head(0), Some(1));
250 assert_eq!(clist.peek_head(0), None);
251 assert_eq!(clist.peek_head(0), None);
252 assert_eq!(clist.pop_head(0), None);
253 assert!(clist.is_empty(0));
254 }
255 }
256}