jurubas/src/xous/services/ticktimer.rs

171 lines
5.2 KiB
Rust

use std::{
collections::HashMap,
sync::{atomic::AtomicUsize, Arc, Condvar, Mutex},
thread,
};
use super::LendResult;
use crate::xous::Memory;
pub struct Ticktimer {
start: std::time::SystemTime,
condvars: HashMap<usize, Arc<(Condvar, AtomicUsize)>>,
}
enum ScalarOpcode {
ElapsedMs = 0,
WaitForCondition = 8,
NotifyCondition = 9,
FreeCondition = 11,
}
impl Ticktimer {
pub fn new() -> Self {
// println!("Constructing a ticktimer");
Ticktimer {
start: std::time::SystemTime::now(),
condvars: HashMap::new(),
}
}
}
impl Default for Ticktimer {
fn default() -> Self {
Self::new()
}
}
impl super::Service for Ticktimer {
fn scalar(&mut self, _memory: &mut Memory, _sender: u32, opcode: u32, args: [u32; 4]) {
if opcode == ScalarOpcode::FreeCondition as u32 {
let condition_index = args[0] as usize;
if let Some(condvar) = self.condvars.remove(&condition_index) {
assert!(condvar.1.load(std::sync::atomic::Ordering::Relaxed) == 0);
}
} else {
println!("Unhandled scalar: {}", opcode);
}
}
fn blocking_scalar(
&mut self,
_memory: &mut Memory,
sender: u32,
opcode: u32,
args: [u32; 4],
) -> super::ScalarResult {
if opcode == ScalarOpcode::ElapsedMs as u32 {
let elapsed_ms = std::time::SystemTime::now()
.duration_since(self.start)
.unwrap()
.as_millis() as u64;
super::ScalarResult::Scalar2([elapsed_ms as u32, (elapsed_ms >> 32) as u32])
} else if opcode == ScalarOpcode::WaitForCondition as u32 {
let condition_index = args[0] as usize;
let wait_count = args[1] as u64;
let (tx, rx) = std::sync::mpsc::channel();
let condvar = self
.condvars
.entry(condition_index)
.or_insert_with(|| Arc::new((Condvar::new(), AtomicUsize::new(0))))
.clone();
condvar.1.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
thread::spawn(move || {
let dummy_mutex = Mutex::new(());
let guard = dummy_mutex.lock().unwrap();
let timeout_value = if wait_count == 0 {
let _ignored = condvar.0.wait(guard).unwrap();
0
} else if condvar
.0
.wait_timeout(guard, std::time::Duration::from_millis(wait_count))
.unwrap()
.1
.timed_out()
{
1
} else {
0
};
condvar.1.fetch_sub(1, std::sync::atomic::Ordering::Relaxed);
tx.send((
[
super::super::definitions::SyscallResultNumber::Scalar1 as i64,
timeout_value,
0,
0,
0,
0,
0,
0,
],
None,
))
.unwrap();
});
super::ScalarResult::WaitForResponse(rx)
} else if opcode == ScalarOpcode::NotifyCondition as u32 {
let condition_index = args[0] as usize;
let condition_count = args[1] as usize;
if condition_count == 0 || !self.condvars.contains_key(&condition_index) {
return super::ScalarResult::Scalar5([0, 0, 0, 0, 0]);
}
let mut notify_count = 0;
if let Some(condvar) = self.condvars.get(&condition_index) {
if condition_count == 0 {
notify_count = condvar.1.load(std::sync::atomic::Ordering::Relaxed);
condvar.0.notify_all();
} else {
for _ in 0..condition_count {
notify_count += 1;
condvar.0.notify_one();
}
}
}
super::ScalarResult::Scalar1(notify_count as u32)
} else {
panic!(
"Ticktimer unhandled blocking_scalar {}: {} {:x?}",
sender, opcode, args
);
}
}
fn lend(
&mut self,
_memory: &mut Memory,
sender: u32,
opcode: u32,
_buf: &[u8],
extra: [u32; 2],
) -> LendResult {
println!("Ticktimer lend {}: {} {:x?}", sender, opcode, extra);
LendResult::MemoryReturned([0, 0])
}
fn lend_mut(
&mut self,
_memory: &mut Memory,
sender: u32,
opcode: u32,
_buf: &mut [u8],
extra: [u32; 2],
) -> LendResult {
println!("Ticktimer lend_mut {}: {} {:x?}", sender, opcode, extra);
LendResult::MemoryReturned([0, 0])
}
fn send(
&mut self,
_memory: &mut Memory,
sender: u32,
opcode: u32,
_buf: &[u8],
extra: [u32; 2],
) {
println!("Ticktimer send {}: {} {:x?}", sender, opcode, extra);
}
}