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