xref: /DragonOS/kernel/src/libs/notifier.rs (revision 729a96ef47f473d535d8317a2ace5ba141fd282a)
1 use crate::{
2     kwarn,
3     libs::{rwlock::RwLock, spinlock::SpinLock},
4     syscall::SystemError,
5 };
6 use alloc::{sync::Arc, vec::Vec};
7 
8 /// @brief 通知链节点
9 pub trait NotifierBlock<T> {
10     /// @brief 通知链中注册的回调函数类型
11     fn notifier_call(&self, action: u64, data: Option<&T>) -> i32;
12     /// @brief 通知链节点的优先级
13     fn priority(&self) -> i32;
14 }
15 
16 /// @brief 通知链
17 // TODO: 考虑使用红黑树封装
18 struct NotifierChain<T>(Vec<Arc<dyn NotifierBlock<T>>>);
19 
20 impl<T> NotifierChain<T> {
21     pub fn new() -> Self {
22         Self(vec![])
23     }
24 
25     /// @brief 将节点注册到通知链
26     /// @param unique_priority 检查通知链中优先级的唯一性
27     pub fn register(
28         &mut self,
29         block: Arc<dyn NotifierBlock<T>>,
30         unique_priority: bool,
31     ) -> Result<(), SystemError> {
32         let mut index: usize = 0;
33 
34         // 在 notifier chain中寻找第一个优先级比要插入块低的块
35         for b in self.0.iter() {
36             // 判断之前是否已经注册过该节点
37             if Arc::as_ptr(&block) == Arc::as_ptr(b) {
38                 kwarn!(
39                     "notifier callback {:?} already registered",
40                     Arc::as_ptr(&block)
41                 );
42                 return Err(SystemError::EEXIST);
43             }
44 
45             if block.priority() > b.priority() {
46                 break;
47             }
48 
49             // 优先级唯一性检测
50             if block.priority() == b.priority() && unique_priority {
51                 return Err(SystemError::EBUSY);
52             }
53 
54             index += 1;
55         }
56 
57         // 插入 notifier chain
58         self.0.insert(index, block);
59         return Ok(());
60     }
61 
62     /// @brief 在通知链中取消注册节点
63     pub fn unregister(&mut self, block: Arc<dyn NotifierBlock<T>>) -> Result<(), SystemError> {
64         let remove = self
65             .0
66             .drain_filter(|b| Arc::as_ptr(&block) == Arc::as_ptr(b));
67         match remove.count() {
68             0 => return Err(SystemError::ENOENT),
69             _ => return Ok(()),
70         }
71     }
72 
73     /// @brief 通知链进行事件通知
74     /// @param nr_to_call 回调函数次数
75     /// @return (最后一次回调函数的返回值,回调次数)
76     // TODO: 增加 NOTIFIER_STOP_MASK 相关功能
77     pub fn call_chain(
78         &self,
79         action: u64,
80         data: Option<&T>,
81         nr_to_call: Option<usize>,
82     ) -> (i32, usize) {
83         let mut ret: i32 = 0;
84         let mut nr_calls: usize = 0;
85 
86         for b in self.0.iter() {
87             if nr_to_call.is_some_and(|x| nr_calls >= x) {
88                 break;
89             }
90             ret = b.notifier_call(action, data);
91             nr_calls += 1;
92         }
93         return (ret, nr_calls);
94     }
95 }
96 
97 /// @brief 原子的通知链,使用 SpinLock 进行同步
98 pub struct AtomicNotifierChain<T>(SpinLock<NotifierChain<T>>);
99 
100 impl<T> AtomicNotifierChain<T> {
101     pub fn new() -> Self {
102         Self(SpinLock::new(NotifierChain::<T>::new()))
103     }
104 
105     pub fn register(&mut self, block: Arc<dyn NotifierBlock<T>>) -> Result<(), SystemError> {
106         let mut notifier_chain_guard = self.0.lock();
107         return notifier_chain_guard.register(block, false);
108     }
109 
110     pub fn register_unique_prio(
111         &mut self,
112         block: Arc<dyn NotifierBlock<T>>,
113     ) -> Result<(), SystemError> {
114         let mut notifier_chain_guard = self.0.lock();
115         return notifier_chain_guard.register(block, true);
116     }
117 
118     pub fn unregister(&mut self, block: Arc<dyn NotifierBlock<T>>) -> Result<(), SystemError> {
119         let mut notifier_chain_guard = self.0.lock();
120         return notifier_chain_guard.unregister(block);
121     }
122 
123     pub fn call_chain(
124         &self,
125         action: u64,
126         data: Option<&T>,
127         nr_to_call: Option<usize>,
128     ) -> (i32, usize) {
129         let notifier_chain_guard = self.0.lock();
130         return notifier_chain_guard.call_chain(action, data, nr_to_call);
131     }
132 }
133 
134 /// @brief 可阻塞的通知链,使用 RwLock 进行同步
135 // TODO: 使用 semaphore 封装
136 pub struct BlockingNotifierChain<T>(RwLock<NotifierChain<T>>);
137 
138 impl<T> BlockingNotifierChain<T> {
139     pub fn new() -> Self {
140         Self(RwLock::new(NotifierChain::<T>::new()))
141     }
142 
143     pub fn register(&mut self, block: Arc<dyn NotifierBlock<T>>) -> Result<(), SystemError> {
144         let mut notifier_chain_guard = self.0.write();
145         return notifier_chain_guard.register(block, false);
146     }
147 
148     pub fn register_unique_prio(
149         &mut self,
150         block: Arc<dyn NotifierBlock<T>>,
151     ) -> Result<(), SystemError> {
152         let mut notifier_chain_guard = self.0.write();
153         return notifier_chain_guard.register(block, true);
154     }
155 
156     pub fn unregister(&mut self, block: Arc<dyn NotifierBlock<T>>) -> Result<(), SystemError> {
157         let mut notifier_chain_guard = self.0.write();
158         return notifier_chain_guard.unregister(block);
159     }
160 
161     pub fn call_chain(
162         &self,
163         action: u64,
164         data: Option<&T>,
165         nr_to_call: Option<usize>,
166     ) -> (i32, usize) {
167         let notifier_chain_guard = self.0.read();
168         return notifier_chain_guard.call_chain(action, data, nr_to_call);
169     }
170 }
171 
172 /// @brief 原始的通知链,由调用者自行考虑同步
173 pub struct RawNotifierChain<T>(NotifierChain<T>);
174 
175 impl<T> RawNotifierChain<T> {
176     pub fn new() -> Self {
177         Self(NotifierChain::<T>::new())
178     }
179 
180     pub fn register(&mut self, block: Arc<dyn NotifierBlock<T>>) -> Result<(), SystemError> {
181         return self.0.register(block, false);
182     }
183 
184     pub fn unregister(&mut self, block: Arc<dyn NotifierBlock<T>>) -> Result<(), SystemError> {
185         return self.0.unregister(block);
186     }
187 
188     pub fn call_chain(
189         &self,
190         action: u64,
191         data: Option<&T>,
192         nr_to_call: Option<usize>,
193     ) -> (i32, usize) {
194         return self.0.call_chain(action, data, nr_to_call);
195     }
196 }
197