starnix_core/task/
delayed_release.rs1use crate::task::CurrentTask;
6use fuchsia_rcu::rcu_run_callbacks;
7use starnix_logging::log_warn;
8use starnix_types::ownership::Releasable;
9use std::cell::RefCell;
10use std::ops::DerefMut;
11
12pub fn register_delayed_release<T: for<'a> Releasable<Context<'a> = &'a CurrentTask> + 'static>(
14 to_release: T,
15) {
16 RELEASERS.with(|cell| {
17 let mut cell = cell.borrow_mut();
18 let list = &mut cell.as_mut().expect("DelayedReleaser hasn't been finalized").releasables;
19 list.push(Box::new(Some(to_release)));
20 });
21}
22
23impl<T> CurrentTaskReleasable for Option<T>
24where
25 for<'a> T: Releasable<Context<'a> = &'a CurrentTask>,
26{
27 fn release_with_context(&mut self, context: &CurrentTask) {
28 if let Some(this) = self.take() {
29 <T as Releasable>::release(this, context);
30 }
31 }
32}
33
34pub trait CurrentTaskReleasable {
36 fn release_with_context(&mut self, context: &CurrentTask);
37}
38
39thread_local! {
40 static RELEASERS: RefCell<Option<LocalReleasers>> =
42 RefCell::new(Some(LocalReleasers::default()));
43}
44
45#[derive(Default)]
46struct LocalReleasers {
47 releasables: Vec<Box<dyn CurrentTaskReleasable>>,
49}
50
51impl LocalReleasers {
52 fn is_empty(&self) -> bool {
53 self.releasables.is_empty()
54 }
55}
56
57impl Releasable for LocalReleasers {
58 type Context<'a> = &'a CurrentTask;
59
60 fn release<'a>(self, context: &'a CurrentTask) {
61 let current_task = context;
62 for mut releasable in self.releasables {
63 releasable.release_with_context(current_task);
64 }
65 }
66}
67
68#[derive(Debug, Default)]
73pub struct DelayedReleaser {}
74
75impl DelayedReleaser {
76 pub fn apply(&self, current_task: &CurrentTask) {
78 let mut counter = 0u32;
79 loop {
80 let ran_rcu = rcu_run_callbacks();
81 let releasers = RELEASERS.with(|cell| {
82 std::mem::take(
83 cell.borrow_mut()
84 .as_mut()
85 .expect("DelayedReleaser hasn't been finalized yet")
86 .deref_mut(),
87 )
88 });
89 if releasers.is_empty() && !ran_rcu {
90 return;
91 }
92 releasers.release(current_task);
93 counter += 1;
94 if counter == 100 {
95 log_warn!("DelayedReleaser: applied >=100 delayed releases");
96 }
97 if counter > 10000 {
98 panic!("DelayedReleaser: applied >10000 delayed releases");
99 }
100 }
101 }
102
103 pub fn finalize() {
109 RELEASERS.with(|cell| {
110 let list = cell.borrow_mut().take().expect("DelayedReleaser hasn't been finalized");
111 assert!(list.is_empty());
112 });
113 }
114}