mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-26 02:43:24 +00:00
Remove the timer module from the aster-frame and adjust the related code
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
d019de29f9
commit
b226928349
@ -27,7 +27,6 @@ extern crate alloc;
|
||||
#[cfg(ktest)]
|
||||
#[macro_use]
|
||||
extern crate ktest;
|
||||
#[macro_use]
|
||||
extern crate static_assertions;
|
||||
|
||||
pub mod arch;
|
||||
@ -43,7 +42,6 @@ pub mod panicking;
|
||||
pub mod prelude;
|
||||
pub mod sync;
|
||||
pub mod task;
|
||||
pub mod timer;
|
||||
pub mod trap;
|
||||
pub mod user;
|
||||
pub mod vm;
|
||||
|
@ -23,5 +23,5 @@ pub use self::{
|
||||
RwMutexReadGuard, RwMutexUpgradeableGuard, RwMutexWriteGuard,
|
||||
},
|
||||
spin::{ArcSpinLockGuard, SpinLock, SpinLockGuard},
|
||||
wait::WaitQueue,
|
||||
wait::{WaitQueue, Waiter, Waker},
|
||||
};
|
||||
|
@ -1,16 +1,10 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use alloc::{collections::VecDeque, sync::Arc};
|
||||
use core::{
|
||||
sync::atomic::{AtomicBool, AtomicU32, Ordering},
|
||||
time::Duration,
|
||||
};
|
||||
use core::sync::atomic::{AtomicBool, AtomicU32, Ordering};
|
||||
|
||||
use super::SpinLock;
|
||||
use crate::{
|
||||
arch::timer::{add_timeout_list, TIMER_FREQ},
|
||||
task::{add_task, current_task, schedule, Task, TaskStatus},
|
||||
};
|
||||
use crate::task::{add_task, current_task, schedule, Task, TaskStatus};
|
||||
|
||||
/// A wait queue.
|
||||
///
|
||||
@ -42,72 +36,44 @@ impl WaitQueue {
|
||||
///
|
||||
/// By taking a condition closure, his wait-wakeup mechanism becomes
|
||||
/// more efficient and robust.
|
||||
pub fn wait_until<F, R>(&self, cond: F) -> R
|
||||
where
|
||||
F: FnMut() -> Option<R>,
|
||||
{
|
||||
self.do_wait(cond, None).unwrap()
|
||||
}
|
||||
|
||||
/// Wait until some condition returns Some(_), or a given timeout is reached. If
|
||||
/// the condition does not becomes Some(_) before the timeout is reached, the
|
||||
/// function will return None.
|
||||
pub fn wait_until_or_timeout<F, R>(&self, cond: F, timeout: &Duration) -> Option<R>
|
||||
where
|
||||
F: FnMut() -> Option<R>,
|
||||
{
|
||||
self.do_wait(cond, Some(timeout))
|
||||
}
|
||||
|
||||
fn do_wait<F, R>(&self, mut cond: F, timeout: Option<&Duration>) -> Option<R>
|
||||
pub fn wait_until<F, R>(&self, mut cond: F) -> R
|
||||
where
|
||||
F: FnMut() -> Option<R>,
|
||||
{
|
||||
if let Some(res) = cond() {
|
||||
return Some(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
let (waiter, waker) = Waiter::new_pair();
|
||||
|
||||
let timer_callback = timeout.map(|timeout| {
|
||||
let remaining_ticks = {
|
||||
// FIXME: We currently require 1000 to be a multiple of TIMER_FREQ, but
|
||||
// this may not hold true in the future, because TIMER_FREQ can be greater
|
||||
// than 1000. Then, the code need to be refactored.
|
||||
const_assert!(1000 % TIMER_FREQ == 0);
|
||||
|
||||
let ms_per_tick = 1000 / TIMER_FREQ;
|
||||
|
||||
// The ticks should be equal to or greater than timeout
|
||||
(timeout.as_millis() as u64 + ms_per_tick - 1) / ms_per_tick
|
||||
};
|
||||
|
||||
add_timeout_list(remaining_ticks, waker.clone(), |timer_call_back| {
|
||||
let waker = timer_call_back.data().downcast_ref::<Arc<Waker>>().unwrap();
|
||||
waker.wake_up();
|
||||
})
|
||||
});
|
||||
|
||||
loop {
|
||||
// Enqueue the waker before checking `cond()` to avoid races
|
||||
self.enqueue(waker.clone());
|
||||
|
||||
if let Some(res) = cond() {
|
||||
if let Some(timer_callback) = timer_callback {
|
||||
timer_callback.cancel();
|
||||
}
|
||||
|
||||
return Some(res);
|
||||
return res;
|
||||
};
|
||||
waiter.wait();
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref timer_callback) = timer_callback
|
||||
&& timer_callback.is_expired()
|
||||
{
|
||||
// Drop the waiter and check again to avoid missing a wake event
|
||||
drop(waiter);
|
||||
return cond();
|
||||
}
|
||||
pub fn wait_until_or_cancelled<F, R>(&self, mut cond: F) -> R
|
||||
where
|
||||
F: FnMut() -> Option<R>,
|
||||
{
|
||||
if let Some(res) = cond() {
|
||||
return res;
|
||||
}
|
||||
|
||||
let (waiter, waker) = Waiter::new_pair();
|
||||
|
||||
loop {
|
||||
// Enqueue the waker before checking `cond()` to avoid races
|
||||
self.enqueue(waker.clone());
|
||||
|
||||
if let Some(res) = cond() {
|
||||
return res;
|
||||
};
|
||||
waiter.wait();
|
||||
}
|
||||
}
|
||||
@ -170,7 +136,7 @@ impl WaitQueue {
|
||||
///
|
||||
/// By definition, a waiter belongs to the current thread, so it cannot be sent to another thread
|
||||
/// and its reference cannot be shared between threads.
|
||||
struct Waiter {
|
||||
pub struct Waiter {
|
||||
waker: Arc<Waker>,
|
||||
}
|
||||
|
||||
@ -181,7 +147,7 @@ impl !Sync for Waiter {}
|
||||
///
|
||||
/// A waker can be created by calling [`Waiter::new`]. This method creates an `Arc<Waker>` that can
|
||||
/// be used across different threads.
|
||||
struct Waker {
|
||||
pub struct Waker {
|
||||
has_woken: AtomicBool,
|
||||
task: Arc<Task>,
|
||||
}
|
||||
@ -271,3 +237,9 @@ impl Waker {
|
||||
self.has_woken.store(true, Ordering::Release);
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Waiter {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
@ -1,105 +0,0 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//! Timer.
|
||||
|
||||
use core::{sync::atomic::Ordering, time::Duration};
|
||||
|
||||
pub use crate::arch::timer::read_monotonic_milli_seconds;
|
||||
use crate::{
|
||||
arch::timer::{add_timeout_list, TimerCallback, TICK, TIMER_FREQ},
|
||||
prelude::*,
|
||||
sync::SpinLock,
|
||||
};
|
||||
|
||||
/// A timer invokes a callback function after a specified span of time elapsed.
|
||||
///
|
||||
/// A new timer is initially inactive. Only after a timeout value is set with
|
||||
/// the `set` method can the timer become active and the callback function
|
||||
/// be triggered.
|
||||
///
|
||||
/// Timers are one-shot. If the time is out, one has to set the timer again
|
||||
/// in order to trigger the callback again.
|
||||
pub struct Timer {
|
||||
function: Arc<dyn Fn(Arc<Self>) + Send + Sync>,
|
||||
inner: SpinLock<TimerInner>,
|
||||
}
|
||||
#[derive(Default)]
|
||||
struct TimerInner {
|
||||
start_tick: u64,
|
||||
timeout_tick: u64,
|
||||
timer_callback: Option<Arc<TimerCallback>>,
|
||||
}
|
||||
|
||||
fn timer_callback(callback: &TimerCallback) {
|
||||
let data = callback.data();
|
||||
if data.is::<Arc<Timer>>() {
|
||||
let timer = data.downcast_ref::<Arc<Timer>>().unwrap();
|
||||
timer.function.call((timer.clone(),));
|
||||
} else {
|
||||
panic!("the timer callback is not Timer structure");
|
||||
}
|
||||
}
|
||||
|
||||
const NANOS_DIVIDE: u64 = 1_000_000_000 / TIMER_FREQ;
|
||||
|
||||
impl Timer {
|
||||
/// Creates a new instance, given a callback function.
|
||||
pub fn new<F>(f: F) -> Result<Arc<Self>>
|
||||
where
|
||||
F: Fn(Arc<Timer>) + Send + Sync + 'static,
|
||||
{
|
||||
Ok(Arc::new(Self {
|
||||
function: Arc::new(f),
|
||||
inner: SpinLock::new(TimerInner::default()),
|
||||
}))
|
||||
}
|
||||
|
||||
/// Set a timeout value.
|
||||
///
|
||||
/// If a timeout value is already set, the timeout value will be refreshed.
|
||||
///
|
||||
pub fn set(self: &Arc<Self>, timeout: Duration) {
|
||||
let mut lock = self.inner.lock_irq_disabled();
|
||||
match &lock.timer_callback {
|
||||
Some(callback) => {
|
||||
callback.cancel();
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
let tick_count =
|
||||
timeout.as_secs() * TIMER_FREQ + timeout.subsec_nanos() as u64 / NANOS_DIVIDE;
|
||||
let tick = TICK.load(Ordering::SeqCst);
|
||||
lock.start_tick = tick;
|
||||
lock.timeout_tick = tick + tick_count;
|
||||
lock.timer_callback = Some(add_timeout_list(tick_count, self.clone(), timer_callback));
|
||||
}
|
||||
|
||||
/// Returns the remaining timeout value.
|
||||
///
|
||||
/// If the timer is not set, then the remaining timeout value is zero.
|
||||
pub fn remain(&self) -> Duration {
|
||||
let lock = self.inner.lock_irq_disabled();
|
||||
let tick_remain = {
|
||||
let tick = TICK.load(Ordering::SeqCst) as i64;
|
||||
lock.timeout_tick as i64 - tick
|
||||
};
|
||||
if tick_remain <= 0 {
|
||||
Duration::new(0, 0)
|
||||
} else {
|
||||
let second_count = tick_remain as u64 / TIMER_FREQ;
|
||||
let remain_count = tick_remain as u64 % TIMER_FREQ;
|
||||
Duration::new(second_count, (remain_count * NANOS_DIVIDE) as u32)
|
||||
}
|
||||
}
|
||||
|
||||
/// Clear the timeout value.
|
||||
pub fn clear(&self) {
|
||||
let mut lock = self.inner.lock_irq_disabled();
|
||||
if let Some(callback) = &lock.timer_callback {
|
||||
callback.cancel();
|
||||
}
|
||||
lock.timeout_tick = 0;
|
||||
lock.start_tick = 0;
|
||||
lock.timer_callback = None;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user