xwrust/xwos/swt.rs
1//! XWOS RUST:软件定时器
2//! ========
3//!
4//! XWOS RUST的软件定时器是基于XWOS内核中的软件定时器来实现的。
5//!
6//! 软件定时器的 **回调函数** 运行在中断上下文或中断底半部上下文,是由硬件的中断驱动的。
7//!
8//! RUST的编译器无法获知硬件的运行状态,所以无法预测 **回调函数** 什么时候会执行,也无法检测软件定时器对象的生命周期。
9//!
10//! 如果 **回调函数** 是闭包,编译器也无法检测捕获环境中引用的生命周期。
11//!
12//! **回调函数** 甚至可能不执行,如果变量移动到 **回调函数** ,有可能因 **回调函数** 不执行而无法被 [`drop()`] 。
13//!
14//!
15//! 因此,软件定时器对象只能定义为静态生命周期的全局变量,软件定时器的 **回调函数** 只能是 [`fn`] 或什么也不捕获的 [`Fn()`] 。
16//!
17//!
18//! # 创建
19//!
20//! XWOS RUST的软件定时器可使用 [`Swt::new()`] 创建。只能创建具有静态生命周期 [`static`] 约束的全局变量:
21//!
22//! ```rust
23//! use xwrust::xwos::swt::*;
24//! use xwrust::xwos::lock::spinlock::*;
25//!
26//! // 创建一个带有自选锁的软件定时器
27//! static SWT: Swt<Spinlock<u32>> = Swt::new(Spinlock::new(1));
28//! ```
29//!
30//!
31//! # 内部数据
32//!
33//! 软件定时器可以携带内部数据 `T` ,由于软件定时器具有静态生命周期,因此内部数据 `T` 也为静态生命周期。
34//! 访问 `T` 时需要上锁,防止不同上下文之间竞争数据。但由于软件定时器的 **回调函数** 只能运行在中断上下文或中断底半部上下文,
35//! 锁只能是 [`Spinlock`] 或 [`Seqlock`] 。
36//!
37//! ```rust
38//! // 内部数据 `T` 为 `Spinlock<u32>`
39//! static SWT: Swt<Spinlock<u32>> = Swt::new(Spinlock::new(1));
40//! ```
41//!
42//!
43//! # 回调函数
44//!
45//! 软件定时器的 **回调函数** 的形式为 `fn(&Swt)` ,其中 `&Swt` 是指向软件定时器自己的一个引用。
46//! 通过此应用,可以访问定时器携带的数据。
47//!
48//! [`Swt::as_ref()`] 可以获取定时器内部数据 `T` 的引用。
49//! [`Swt::as_mut()`] 可以获取定时器内部数据 `T` 的可变引用。
50//!
51//!
52//! # 启动
53//!
54//! 软件定时器由两种启动方式:
55//!
56//! [`Swt::once()`] 软件定时器只会运行一次;
57//! [`Swt::repeat()`] 软件定时器会重复运行。
58//!
59//!
60//! # 停止
61//!
62//! [`Swt::stop()`] 可用于停止软件定时器,若软件定时器未到达超时时间,回调函数不会被调用。
63//!
64//!
65//! [`drop()`]: <https://doc.rust-lang.org/core/ops/trait.Drop.html#tymethod.drop>
66//! [`fn()`]: https://doc.rust-lang.org/std/keyword.fn.html
67//! [`Fn()`]: https://doc.rust-lang.org/core/ops/trait.Fn.html
68//! [`static`]: <https://doc.rust-lang.org/std/keyword.static.html>
69//! [`Spinlock`]: crate::xwos::lock::spinlock::Spinlock
70//! [`Seqlock`]: crate::xwos::lock::seqlock::Seqlock
71
72extern crate core;
73use core::ffi::*;
74use core::option::Option;
75use core::cell::UnsafeCell;
76use core::convert::AsRef;
77use core::convert::AsMut;
78
79use crate::types::*;
80
81extern "C" {
82 fn xwrustffi_swt_once(swt: *mut XwosSwt,
83 origin: XwTm,
84 period: XwTm,
85 callback: extern "C" fn(*mut XwosSwt, *mut c_void),
86 arg: *mut c_void) -> XwEr;
87
88 fn xwrustffi_swt_repeat(swt: *mut XwosSwt,
89 origin: XwTm,
90 period: XwTm,
91 callback: extern "C" fn(*mut XwosSwt, *mut c_void),
92 arg: *mut c_void) -> XwEr;
93
94 fn xwrustffi_swt_stop(swt: *mut XwosSwt) -> XwEr;
95}
96
97/// XWOS软件定时器对象占用的内存大小
98#[cfg(target_pointer_width = "32")]
99pub const SIZEOF_XWOS_SWT: usize = 96;
100
101/// XWOS软件定时器占用的内存大小
102#[cfg(target_pointer_width = "64")]
103pub const SIZEOF_XWOS_SWT: usize = 192;
104
105/// 用于构建软件定时器的内存数组类型
106#[repr(C)]
107#[cfg_attr(target_pointer_width = "32", repr(align(8)))]
108#[cfg_attr(target_pointer_width = "64", repr(align(16)))]
109pub(crate) struct XwosSwt {
110 pub(crate) obj: [u8; SIZEOF_XWOS_SWT],
111}
112
113/// 用于构建软件定时器的内存数组常量
114///
115/// 此常量的作用是告诉编译器软件定时器对象需要多大的内存。
116pub(crate) const XWOS_SWT_INITIALIZER: XwosSwt = XwosSwt {
117 obj: [0; SIZEOF_XWOS_SWT],
118};
119
120/// 软件定时器对象结构体
121pub struct Swt<T> {
122 /// 用于初始化XWOS软件定时器对象的内存空间
123 pub(crate) swt: UnsafeCell<XwosSwt>,
124 /// 软件定时器对象的标签
125 pub(crate) tik: UnsafeCell<XwSq>,
126 /// 回调函数
127 pub(crate) cb: UnsafeCell<Option<fn(&Self)>>,
128 /// 数据
129 pub(crate) data: UnsafeCell<T>,
130}
131
132impl<T> !Send for Swt<T> {}
133
134unsafe impl<T> Sync for Swt<T> {}
135
136impl<T> Swt<T> {
137 /// 新建软件定时器对象
138 ///
139 /// 此方法是编译期方法。
140 ///
141 /// # 参数说明
142 ///
143 /// + d: 定时器附带的数据
144 ///
145 /// # 示例
146 ///
147 /// 软件定时器只能作为静态生命周期 [`static`] 的全局变量:
148 ///
149 /// ```rust
150 /// use xwrust::xwos::swt::*;
151 /// use xwrust::xwos::lock::spinlock::*;
152 ///
153 /// // 创建一个带有自选锁的软件定时器
154 /// static SWT: Swt<Spinlock<u32>> = Swt::new(Spinlock::new(1));
155 /// ```
156 ///
157 /// [`static`]: https://doc.rust-lang.org/std/keyword.static.html
158 pub const fn new(d: T) -> Self {
159 Self {
160 swt: UnsafeCell::new(XWOS_SWT_INITIALIZER),
161 tik: UnsafeCell::new(0),
162 cb: UnsafeCell::new(None),
163 data: UnsafeCell::new(d),
164 }
165 }
166
167 /// 启动软件定时器,并且软件定时器只运行一次
168 ///
169 /// 软件定时器的超时时间由 `origin` + `period` 决定。
170 /// `origin` 是时间的起点, `period` 是时间的增量。
171 ///
172 /// 超时后,回调函数 `cb` 会被调用,且 `cb` 运行在中断上下文或中断底半部上下文。其中不可使用任何会导致阻塞睡眠的方法。
173 ///
174 /// 例如 [`Mutex::lock()`] , [`Sem::wait()`] , [`cthd::sleep()`] , [`println!()`] 等。
175 ///
176 ///
177 /// `cb` 只能是函数或不捕获任何东西的闭包。
178 ///
179 /// # 参数说明
180 ///
181 /// + origin: 时间的起点
182 /// + period: 时间的增量
183 /// + cb: 定时器回调函数
184 ///
185 /// # 示例
186 ///
187 ///
188 /// ```rust
189 /// pub fn xwrust_example_swt() {
190 /// SWT.once(xwtm::now(), xwtm::ms(200), |swt| {
191 /// // 回调函数
192 /// });
193 /// }
194 /// ```
195 ///
196 /// [`Mutex::lock()`]: crate::xwos::lock::mtx::Mutex::lock
197 /// [`Sem::wait()`]: crate::xwos::sync::sem::Sem::wait
198 /// [`cthd::sleep()`]: crate::xwos::cthd::sleep
199 /// [`println!()`]: <https://docs.rs/libc-print/latest/libc_print/macro.libc_print.html>
200 pub fn once(&'static self,
201 origin: XwTm, period: XwTm,
202 cb: fn(&Swt<T>)) {
203 unsafe {
204 *self.cb.get() = Some(cb);
205 let _ = xwrustffi_swt_once(self.swt.get(),
206 origin, period,
207 Swt::<T>::xwrustffi_swt_callback_entry,
208 self as *const Swt<T> as _);
209 }
210 }
211
212 /// 启动软件定时器,并且软件定时器可重复运行
213 ///
214 /// 软件定时器的超时时间由 `origin` + `period` 决定。
215 /// `origin` 是时间的起点, `period` 是时间的增量。
216 ///
217 /// 超时后软件定时器会在超时的时间点上再次增加 `period` 重启软件定时器并执行回调函数 `cb` ,
218 /// 也就是 `cb` 会以 `period` 为周期重复执行。
219 ///
220 ///
221 /// 回调函数 `cb` 运行在中断上下文或中断底半部上下文。其中不可使用任何会导致阻塞睡眠的方法。
222 ///
223 /// 例如 [`Mutex::lock()`] , [`Sem::wait()`] , [`cthd::sleep()`] , [`println!()`] 等。
224 ///
225 ///
226 /// `cb` 只能是函数或不捕获任何东西的闭包。
227 ///
228 /// # 参数说明
229 ///
230 /// + origin: 时间的起点
231 /// + period: 时间的增量
232 /// + cb: 定时器回调函数
233 ///
234 /// # 示例
235 ///
236 ///
237 /// ```rust
238 /// pub fn xwrust_example_swt() {
239 /// SWT.repeat(xwtm::now(), xwtm::ms(200), |swt| {
240 /// // 回调函数
241 /// });
242 /// }
243 /// ```
244 ///
245 /// [`Mutex::lock()`]: crate::xwos::lock::mtx::Mutex::lock
246 /// [`Sem::wait()`]: crate::xwos::sync::sem::Sem::wait
247 /// [`cthd::sleep()`]: crate::xwos::cthd::sleep
248 /// [`println!()`]: <https://docs.rs/libc-print/latest/libc_print/macro.libc_print.html>
249 pub fn repeat(&'static self,
250 origin: XwTm, period: XwTm,
251 cb: fn(&Swt<T>)) {
252 unsafe {
253 *self.cb.get() = Some(cb);
254 let _ = xwrustffi_swt_repeat(self.swt.get(),
255 origin, period,
256 Swt::<T>::xwrustffi_swt_callback_entry,
257 self as *const Swt<T> as _);
258 }
259 }
260
261 extern "C" fn xwrustffi_swt_callback_entry(_: *mut XwosSwt, arg: *mut c_void) {
262 unsafe {
263 let swt: &Swt<T> = &*(arg as *const Swt<T>);
264 let cb = (*swt.cb.get()).unwrap();
265 cb(swt);
266 *swt.cb.get() = Some(cb);
267 }
268 }
269
270 /// 停止软件定时器
271 ///
272 /// 若软件定时器未到达超时时间,回调函数不会被调用。
273 pub fn stop(&'static self) {
274 unsafe {
275 xwrustffi_swt_stop(self.swt.get());
276 }
277 }
278}
279
280impl<T> AsRef<T> for Swt<T> {
281 fn as_ref(&self) -> &T {
282 unsafe {
283 &*self.data.get()
284 }
285 }
286}
287
288impl<T> AsMut<T> for Swt<T> {
289 fn as_mut(&mut self) -> &mut T {
290 unsafe {
291 &mut *self.data.get()
292 }
293 }
294}