Use RcuOption for lazy-initialized soft-IRQ callbacks

This commit is contained in:
Zhang Junyang 2024-11-13 21:28:58 +08:00 committed by Tate, Hongliang Tian
parent a5065d878e
commit 78a695f21b
2 changed files with 51 additions and 21 deletions

View File

@ -225,14 +225,18 @@ macro_rules! define_timer_managers {
fn _init_system_wide_timer_managers() {
$(
let clock = paste! {[<$clock_id _INSTANCE>].get().unwrap().clone()};
let clock_manager = TimerManager::new(clock);
let timer_manager = TimerManager::new(clock);
for cpu in ostd::cpu::all_cpus() {
paste! {
[<$clock_id _MANAGER>].get_on_cpu(cpu).call_once(|| clock_manager.clone());
[<$clock_id _MANAGER>].get_on_cpu(cpu).call_once(|| timer_manager.clone());
}
}
let callback = move || {
clock_manager.process_expired_timers();
let callback = || {
let preempt_guard = ostd::task::disable_preempt();
let cpu = preempt_guard.current_cpu();
paste! {
[<$clock_id _MANAGER>].get_on_cpu(cpu).get().unwrap().process_expired_timers();
}
};
time::softirq::register_callback(callback);
)*
@ -267,10 +271,13 @@ pub static JIFFIES_TIMER_MANAGER: Once<Arc<TimerManager>> = Once::new();
fn init_jiffies_clock_manager() {
let jiffies_clock = JiffiesClock { _private: () };
let jiffies_timer_manager = TimerManager::new(Arc::new(jiffies_clock));
JIFFIES_TIMER_MANAGER.call_once(|| jiffies_timer_manager.clone());
JIFFIES_TIMER_MANAGER.call_once(|| jiffies_timer_manager);
let callback = move || {
jiffies_timer_manager.process_expired_timers();
let callback = || {
JIFFIES_TIMER_MANAGER
.get()
.unwrap()
.process_expired_timers();
};
time::softirq::register_callback(callback);
}

View File

@ -1,15 +1,13 @@
// SPDX-License-Identifier: MPL-2.0
use alloc::{boxed::Box, vec::Vec};
use alloc::{boxed::Box, vec, vec::Vec};
use aster_softirq::{softirq_id::TIMER_SOFTIRQ_ID, SoftIrqLine};
use ostd::{
sync::{LocalIrqDisabled, RwLock},
timer,
};
use ostd::{sync::RcuOption, timer};
static TIMER_SOFTIRQ_CALLBACKS: RwLock<Vec<Box<dyn Fn() + Sync + Send>>, LocalIrqDisabled> =
RwLock::new(Vec::new());
#[allow(clippy::type_complexity)]
#[allow(clippy::box_collection)]
static TIMER_SOFTIRQ_CALLBACKS: RcuOption<Box<Vec<fn()>>> = RcuOption::new_none();
pub(super) fn init() {
SoftIrqLine::get(TIMER_SOFTIRQ_ID).enable(timer_softirq_handler);
@ -20,16 +18,41 @@ pub(super) fn init() {
}
/// Registers a function that will be executed during timer softirq.
pub(super) fn register_callback<F>(func: F)
where
F: Fn() + Sync + Send + 'static,
pub(super) fn register_callback(func: fn()) {
loop {
let callbacks = TIMER_SOFTIRQ_CALLBACKS.read();
match callbacks.get() {
// Initialized, copy the vector, push the function and update.
Some(callbacks_vec) => {
let mut callbacks_cloned = callbacks_vec.clone();
callbacks_cloned.push(func);
if callbacks
.compare_exchange(Some(Box::new(callbacks_cloned)))
.is_ok()
{
TIMER_SOFTIRQ_CALLBACKS.write().push(Box::new(func));
break;
}
}
// Uninitialized, initialize it.
None => {
if callbacks
.compare_exchange(Some(Box::new(vec![func])))
.is_ok()
{
break;
}
}
}
// Contention on initialization or pushing, retry.
core::hint::spin_loop();
}
}
fn timer_softirq_handler() {
let callbacks = TIMER_SOFTIRQ_CALLBACKS.read();
if let Some(callbacks) = callbacks.get() {
for callback in callbacks.iter() {
(callback)();
}
}
}