Skip to main content

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}