use avr_oxide::util::datatypes::{VolatileBitField, BitIndex, BitFieldAccess};
use avr_oxide::concurrency::interrupt;
use avr_oxide::concurrency::scheduler;
use avr_oxide::deviceconsts::oxide;
pub type ThreadId = usize;
#[repr(C)]
pub struct ThreadSet {
threadids: VolatileBitField
}
const THREADSET_SIZE: usize = oxide::MAX_THREADS;
impl ThreadSet {
pub fn new() -> Self {
ThreadSet {
threadids: VolatileBitField::all_clr()
}
}
pub fn add_thread(&mut self, isotoken: interrupt::token::Isolated, id: ThreadId){
self.threadids.set_isolated(isotoken, BitIndex::bit(id));
}
pub fn add_current_thread(&mut self, isotoken: interrupt::token::Isolated){
self.add_thread(isotoken, scheduler::current_thread_id(isotoken));
}
pub fn remove_thread(&mut self, isotoken: interrupt::token::Isolated, id: ThreadId){
self.threadids.clr_isolated(isotoken, BitIndex::bit(id));
}
pub fn remove_current_thread(&mut self, isotoken: interrupt::token::Isolated){
self.remove_thread(isotoken, scheduler::current_thread_id(isotoken));
}
pub fn contains_thread(&self, _isotoken: interrupt::token::Isolated, id: ThreadId) -> bool {
self.threadids.is_set(BitIndex::bit(id))
}
pub fn contains_current_thread(&self, isotoken: interrupt::token::Isolated) -> bool {
self.contains_thread(isotoken, scheduler::current_thread_id(isotoken))
}
pub fn remove_all(&mut self) {
self.threadids.clr_all()
}
pub fn do_each<F>(&self, isotoken: interrupt::token::Isolated, mut f: F)
where
F: FnMut(interrupt::token::Isolated, ThreadId) -> bool
{
for id in 0..THREADSET_SIZE {
if self.contains_thread(isotoken, id) {
let cont = (f)(isotoken, id);
if !cont {
break;
}
}
}
}
pub fn do_each_consuming<F>(&mut self, isotoken: interrupt::token::Isolated, mut f: F)
where
F: FnMut(interrupt::token::Isolated, ThreadId) -> bool
{
for id in 0..THREADSET_SIZE {
if self.contains_thread(isotoken, id) {
let cont = (f)(isotoken, id);
self.remove_thread(isotoken, id);
if !cont {
break;
}
}
}
}
}
#[cfg(test)]
mod tests {
use std::fmt::{Debug, Formatter};
use avr_oxide::concurrency::util::{ThreadId, ThreadSet};
use avr_oxide::deviceconsts::oxide::MAX_THREADS;
#[test]
fn test_threadset() {
let mut threadset = ThreadSet::new();
assert!(MAX_THREADS >= 4);
avr_oxide::concurrency::interrupt::isolated(|isotoken|{
threadset.add_thread(isotoken, 1u8.into());
threadset.add_thread(isotoken, 3u8.into());
assert!(!threadset.contains_thread(isotoken,0u8.into()));
assert!(threadset.contains_thread(isotoken, 1u8.into()));
assert!(!threadset.contains_thread(isotoken, 2u8.into()));
assert!(threadset.contains_thread(isotoken, 3u8.into()));
})
}
#[test]
fn test_threadset_doeach() {
let mut threadset = ThreadSet::new();
assert!(MAX_THREADS >= 4);
avr_oxide::concurrency::interrupt::isolated(|isotoken|{
threadset.add_thread(isotoken, 1u8.into());
threadset.add_thread(isotoken, 3u8.into());
println!("Testing threadset do_each:");
let mut total = 0usize;
threadset.do_each(isotoken, |isotoken,thread_id|{
total += thread_id;
println!("Iterating - thread id {:?}", thread_id);
assert_ne!(thread_id, 0u8.into());
assert_ne!(thread_id, 2u8.into());
true
});
assert_eq!(total, 4);
assert!(threadset.contains_thread(isotoken,1u8.into()));
assert!(threadset.contains_thread(isotoken, 3u8.into()));
println!("Testing threadset do_each_consuming:");
total = 0;
threadset.do_each_consuming(isotoken, |isotoken,thread_id|{
total += thread_id;
println!("Iterating - thread id {:?}", thread_id);
assert_ne!(thread_id, 0u8.into());
assert_ne!(thread_id, 2u8.into());
true
});
assert_eq!(total, 4);
assert!(!threadset.contains_thread(isotoken,0u8.into()));
assert!(!threadset.contains_thread(isotoken,1u8.into()));
assert!(!threadset.contains_thread(isotoken,2u8.into()));
assert!(!threadset.contains_thread(isotoken, 3u8.into()));
})
}
}