From ab2ea4d31312f463fcae3a3770a954e79cbe2ce1 Mon Sep 17 00:00:00 2001 From: eupn Date: Fri, 21 Apr 2023 19:18:59 +0400 Subject: [PATCH] ticktimer: move some functions into impl modules It will allow implementations to override these functions when desired. --- services/xous-ticktimer/src/main.rs | 99 ++----------------- .../src/platform/hosted/implementation.rs | 79 +++++++++++++++ .../src/platform/precursor/implementation.rs | 83 ++++++++++++++++ 3 files changed, 171 insertions(+), 90 deletions(-) diff --git a/services/xous-ticktimer/src/main.rs b/services/xous-ticktimer/src/main.rs index 7bc537034..612ac0229 100644 --- a/services/xous-ticktimer/src/main.rs +++ b/services/xous-ticktimer/src/main.rs @@ -17,85 +17,6 @@ use platform::*; #[cfg(not(target_arch = "arm"))] use susres::SuspendOrder; -/// Disable the sleep interrupt and remove the currently-pending sleep item. -/// If the sleep item has fired, then there will be no existing sleep item -/// remaining. -fn stop_sleep( - ticktimer: &mut XousTickTimer, - sleep_heap: &mut BTreeMap, // min-heap with Reverse -) { - // If there's a sleep request ongoing now, grab it. - if let Some(current) = ticktimer.stop_interrupt() { - #[cfg(feature = "debug-print")] - info!("Existing request was {:?}", current); - sleep_heap.insert(current.msec, current); - } else { - #[cfg(feature = "debug-print")] - info!("There was no existing sleep() request"); - } -} - -fn start_sleep( - ticktimer: &mut XousTickTimer, - sleep_heap: &mut BTreeMap, // min-heap with Reverse -) { - // If there are items in the sleep heap, take the next item that will expire. - if let Some((_msec, next_response)) = sleep_heap.pop_first() { - #[cfg(feature = "debug-print")] - info!( - "scheduling a response at {} to {} (heap: {:?})", - next_response.msec, next_response.sender, sleep_heap - ); - ticktimer.schedule_response(next_response); - } else { - #[cfg(feature = "debug-print")] - info!( - "not scheduling a response since the sleep heap is empty ({:?})", - sleep_heap - ); - } -} - -/// Recalculate the sleep timer, optionally adding a new Request to the list of available -/// sleep events. This involves stopping the timer, recalculating the newest item, then -/// restarting the timer. -/// -/// Note that interrupts are always enabled, which is why we must stop the timer prior to -/// reordering the list. -fn recalculate_sleep( - ticktimer: &mut XousTickTimer, - sleep_heap: &mut BTreeMap, // min-heap with Reverse - new: Option, -) { - stop_sleep(ticktimer, sleep_heap); - - ticktimer.clear_last_response(); - - // If we have a new sleep request, add it to the heap. - if let Some(mut request) = new { - #[cfg(feature = "debug-print")] - info!("New sleep request was: {:?}", request); - - // Ensure that each timeout only exists once inside the tree - #[cfg(not(feature = "atsama5d27"))] - { - request.msec += ticktimer.elapsed_ms() as i64; - } - while sleep_heap.contains_key(&request.msec) { - request.msec += 1; - } - - #[cfg(feature = "debug-print")] - info!("Modified, the request was: {:?}", request); - sleep_heap.insert(request.msec, request); - } else { - #[cfg(feature = "debug-print")] - info!("No new sleep request"); - } - - start_sleep(ticktimer, sleep_heap); -} - fn main() -> ! { log_server::init_wait().unwrap(); log::set_max_level(log::LevelFilter::Info); @@ -228,12 +149,11 @@ fn main() -> ! { core::mem::forget(msg_opt.take()); // let timeout_queue = timeout_heap.entry(msg.sender.pid()).or_default(); - recalculate_sleep( - &mut ticktimer, + ticktimer.recalculate_sleep( &mut sleep_heap, Some(TimerRequest { msec: ms, - sender: sender, + sender, kind: RequestKind::Sleep, data: 0, }), @@ -245,7 +165,7 @@ fn main() -> ! { if msg.sender.pid().map(|p| p.get()).unwrap_or_default() as u32 != xous::process::id() { - recalculate_sleep(&mut ticktimer, &mut sleep_heap, None); + ticktimer.recalculate_sleep(&mut sleep_heap, None); continue; } @@ -295,7 +215,7 @@ fn main() -> ! { // ); // log::trace!("new entries for PID {:?}/condvar {:08x}: {:?}", sender_pid, condvar, notify_hash.get(&sender_pid).unwrap().get(&condvar)); } - recalculate_sleep(&mut ticktimer, &mut sleep_heap, None); + ticktimer.recalculate_sleep(&mut sleep_heap, None); } api::Opcode::SuspendResume => xous::msg_scalar_unpack!(msg, _token, _, _, _, { @@ -450,8 +370,7 @@ fn main() -> ! { // If there's a `timeout` argument, schedule a response. if timeout != 0 { - recalculate_sleep( - &mut ticktimer, + ticktimer.recalculate_sleep( &mut sleep_heap, Some(TimerRequest { msec: timeout as i64, @@ -516,7 +435,7 @@ fn main() -> ! { log::error!("requested to wake no entries!"); } - stop_sleep(&mut ticktimer, &mut sleep_heap); + ticktimer.stop_sleep(&mut sleep_heap); for entry in awaiting.drain(..available_count) { // Remove each entry in the timeout set sleep_heap.retain(|_, v| v.sender != entry); @@ -564,7 +483,7 @@ fn main() -> ! { // Resume sleeping, which re-enables interrupts and queues the // next timer event to fire. - start_sleep(&mut ticktimer, &mut sleep_heap); + ticktimer.start_sleep(&mut sleep_heap); } api::Opcode::FreeCondition => { @@ -598,7 +517,7 @@ fn main() -> ! { } // Free all entries in the sleep heap that are waiting for this condition - stop_sleep(&mut ticktimer, &mut sleep_heap); + ticktimer.stop_sleep(&mut sleep_heap); for entry in awaiting.drain(..) { // Remove each entry in the timeout set sleep_heap.retain(|_, v| v.sender != entry); @@ -632,7 +551,7 @@ fn main() -> ! { } // Resume sleeping - start_sleep(&mut ticktimer, &mut sleep_heap); + ticktimer.start_sleep(&mut sleep_heap); } api::Opcode::InvalidCall => { diff --git a/services/xous-ticktimer/src/platform/hosted/implementation.rs b/services/xous-ticktimer/src/platform/hosted/implementation.rs index fb71f30d7..fbd78e84c 100644 --- a/services/xous-ticktimer/src/platform/hosted/implementation.rs +++ b/services/xous-ticktimer/src/platform/hosted/implementation.rs @@ -1,8 +1,10 @@ use crate::RequestKind; use crate::TimerRequest; +use crate::TimeoutExpiry; use num_traits::ToPrimitive; use std::convert::TryInto; +use std::collections::BTreeMap; #[derive(Debug)] enum SleepComms { @@ -150,4 +152,81 @@ impl XousTickTimer { } pub fn suspend(&self) {} pub fn resume(&self) {} + + /// Disable the sleep interrupt and remove the currently-pending sleep item. + /// If the sleep item has fired, then there will be no existing sleep item + /// remaining. + pub fn stop_sleep( + &mut self, + sleep_heap: &mut BTreeMap, // min-heap with Reverse + ) { + // If there's a sleep request ongoing now, grab it. + if let Some(current) = self.stop_interrupt() { + #[cfg(feature = "debug-print")] + log::info!("Existing request was {:?}", current); + sleep_heap.insert(current.msec, current); + } else { + #[cfg(feature = "debug-print")] + log::info!("There was no existing sleep() request"); + } + } + + pub fn start_sleep( + &mut self, + sleep_heap: &mut BTreeMap, // min-heap with Reverse + ) { + // If there are items in the sleep heap, take the next item that will expire. + if let Some((_msec, next_response)) = sleep_heap.pop_first() { + #[cfg(feature = "debug-print")] + log::info!( + "scheduling a response at {} to {} (heap: {:?})", + next_response.msec, next_response.sender, sleep_heap + ); + + self.schedule_response(next_response); + } else { + #[cfg(feature = "debug-print")] + log::info!( + "not scheduling a response since the sleep heap is empty ({:?})", + sleep_heap + ); + } + } + + /// Recalculate the sleep timer, optionally adding a new Request to the list of available + /// sleep events. This involves stopping the timer, recalculating the newest item, then + /// restarting the timer. + /// + /// Note that interrupts are always enabled, which is why we must stop the timer prior to + /// reordering the list. + pub fn recalculate_sleep( + &mut self, + sleep_heap: &mut BTreeMap, // min-heap with Reverse + new: Option, + ) { + self.stop_sleep(sleep_heap); + log::trace!("Elapsed: {}", self.elapsed_ms()); + self.clear_last_response(); + + // If we have a new sleep request, add it to the heap. + if let Some(mut request) = new { + #[cfg(feature = "debug-print")] + log::info!("New sleep request was: {:?}", request); + + // Ensure that each timeout only exists once inside the tree + request.msec += self.elapsed_ms() as i64; + while sleep_heap.contains_key(&request.msec) { + request.msec += 1; + } + + #[cfg(feature = "debug-print")] + log::info!("Modified, the request was: {:?}", request); + sleep_heap.insert(request.msec, request); + } else { + #[cfg(feature = "debug-print")] + log::info!("No new sleep request"); + } + + self.start_sleep(sleep_heap); + } } diff --git a/services/xous-ticktimer/src/platform/precursor/implementation.rs b/services/xous-ticktimer/src/platform/precursor/implementation.rs index 1efad232e..96e27eaa2 100644 --- a/services/xous-ticktimer/src/platform/precursor/implementation.rs +++ b/services/xous-ticktimer/src/platform/precursor/implementation.rs @@ -1,5 +1,10 @@ const TICKS_PER_MS: u64 = 1; + +use std::collections::BTreeMap; + use crate::TimerRequest; +use crate::TimeoutExpiry; + use susres::{RegManager, RegOrField, SuspendResume}; use utralib::generated::*; @@ -228,4 +233,82 @@ impl XousTickTimer { self.csr.r(utra::ticktimer::MSLEEP_TARGET0) ); } + + + /// Disable the sleep interrupt and remove the currently-pending sleep item. + /// If the sleep item has fired, then there will be no existing sleep item + /// remaining. + pub fn stop_sleep( + &mut self, + sleep_heap: &mut BTreeMap, // min-heap with Reverse + ) { + // If there's a sleep request ongoing now, grab it. + if let Some(current) = self.stop_interrupt() { + #[cfg(feature = "debug-print")] + log::info!("Existing request was {:?}", current); + sleep_heap.insert(current.msec, current); + } else { + #[cfg(feature = "debug-print")] + log::info!("There was no existing sleep() request"); + } + } + + pub fn start_sleep( + &mut self, + sleep_heap: &mut BTreeMap, // min-heap with Reverse + ) { + // If there are items in the sleep heap, take the next item that will expire. + if let Some((_msec, next_response)) = sleep_heap.pop_first() { + #[cfg(feature = "debug-print")] + log::info!( + "scheduling a response at {} to {} (heap: {:?})", + next_response.msec, next_response.sender, sleep_heap + ); + + self.schedule_response(next_response); + } else { + #[cfg(feature = "debug-print")] + log::info!( + "not scheduling a response since the sleep heap is empty ({:?})", + sleep_heap + ); + } + } + + /// Recalculate the sleep timer, optionally adding a new Request to the list of available + /// sleep events. This involves stopping the timer, recalculating the newest item, then + /// restarting the timer. + /// + /// Note that interrupts are always enabled, which is why we must stop the timer prior to + /// reordering the list. + pub fn recalculate_sleep( + &mut self, + sleep_heap: &mut BTreeMap, // min-heap with Reverse + new: Option, + ) { + self.stop_sleep(sleep_heap); + log::trace!("Elapsed: {}", self.elapsed_ms()); + self.clear_last_response(); + + // If we have a new sleep request, add it to the heap. + if let Some(mut request) = new { + #[cfg(feature = "debug-print")] + log::info!("New sleep request was: {:?}", request); + + // Ensure that each timeout only exists once inside the tree + request.msec += self.elapsed_ms() as i64; + while sleep_heap.contains_key(&request.msec) { + request.msec += 1; + } + + #[cfg(feature = "debug-print")] + log::info!("Modified, the request was: {:?}", request); + sleep_heap.insert(request.msec, request); + } else { + #[cfg(feature = "debug-print")] + log::info!("No new sleep request"); + } + + self.start_sleep(sleep_heap); + } }