Skip to main content

xwrust/xwos/lock/
seqlock.rs

1//! XWOS RUST:顺序锁
2//! ========
3//!
4//! 顺序锁是对自旋锁改良后的锁,顺序锁中包含一个自旋锁,并且带有一个顺序值。
5//! 顺序锁将临界区分为三种:
6//!
7//! #### 独占写
8//!
9//! 任何对顺序锁临界区的 **写** 操作都是独占的,每次 **写** 操作时,会先上锁自旋锁,
10//! 然后增加顺序值,离开临界区时也会再次增加顺序值。言外之意,顺序值增加两次,顺序值增加的次数是 **偶数** 。
11//!
12//! 锁的模式:
13//!
14//! + 当临界区只被多个线程访问时,需使用关闭抢占的模式: [`SeqlockMode::WriteLock`]
15//! + 当临界区被中断底半部访问时,需使用关闭中断底半部的模式: [`SeqlockMode::WriteLockBh`]
16//! + 当临界区被多个线程和单一中断访问时,需使用关闭中断的模式: [`SeqlockMode::WriteLockCpuirq`]
17//! + 当临界区被多个中断上下文访问时,需使用保存中断标志的模式: [`SeqlockMode::WriteLockCpuirqSave(None)`]
18//!
19//! #### 非独占读
20//!
21//! 如果多个CPU进行的是 **只读** 操作,它们可以同时进入 **非独占读临界区** 。
22//! CPU进入非独占读临界区无需获得自旋锁,但需要先测试顺序值是否为 **偶数**,并记录此时的顺序值。
23//! 当退出读临界区时,需要再次读取顺序值,并与之前记录的值进行比较:
24//!
25//! + 如果相等,表示读的结果有效;
26//! + 如果不相等,则表示读的过程中别的CPU进行了写操作,此次的读操作无效。
27//!
28//! #### 独占读
29//!
30//! 如果希望读临界区不会被写操作无效掉,可以使用独占读的方式,
31//! 独占读会排斥其他CPU上的独占写和独占读操作,但不会排斥非独占读,
32//! 其他CPU依然可以进入非独占读临界区。
33//!
34//! 锁的模式 :
35//!
36//! + 当临界区只被多个线程访问时,需使用关闭抢占的模式: [`SeqlockMode::ReadExclusiveLock`]
37//! + 当临界区被中断底半部访问时,需使用关闭中断底半部的模式: [`SeqlockMode::ReadExclusiveLockBh`]
38//! + 当临界区被多个线程和单一中断访问时,需使用关闭中断的模式: [`SeqlockMode::ReadExclusiveLockCpuirq`]
39//! + 当临界区被多个中断上下文访问时,需使用保存中断标志的模式: [`SeqlockMode::ReadExclusiveLockCpuirqSave(None)`]
40//!
41//!
42//! # 创建
43//!
44//! XWOS RUST的顺序锁可使用 [`Seqlock::new()`] 创建。
45//!
46//! + 可以创建具有静态生命周期 [`static`] 约束的全局变量:
47//!
48//! ```rust
49//! use xwrust::xwos::lock::seqlock::*;
50//!
51//! static GLOBAL_SEQLOCK: Seqlock<u32> = Seqlock::new(0);
52//! ```
53//!
54//! + 也可以使用 [`alloc::sync::Arc`] 在heap中创建:
55//!
56//! ```rust
57//! extern crate alloc;
58//! use alloc::sync::Arc;
59//!
60//! use xwrust::xwos::lock::seqlock::*;
61//!
62//! pub fn xwrust_example_seqlock() {
63//!     let seqlock: Arc<Seqlock<u32>> = Arc::new(Seqlock::new(0));
64//! }
65//! ```
66//!
67//!
68//! # 解锁
69//!
70//! 上锁后返回的 [`SeqlockGuard`] 。 [`SeqlockGuard`] 的生命周期结束时,会自动解锁。
71//! 也可调用 [`Seqlock::unlock()`] 主动消费掉 [`SeqlockGuard`] 来解锁。
72//!
73//!
74//! # 上锁
75//!
76//! 上锁的方法 [`Seqlock::lock()`] 除了 **自旋** 等待,改变顺序值外,还会根据上锁模式增加额外操作:
77//!
78//! + 只关闭抢占的模式: [`SeqlockMode::WriteLock`] 以及 [`SeqlockMode::ReadExclusiveLock`]
79//! + 关闭中断底半部的模式: [`SeqlockMode::WriteLockBh`] 以及 [`SeqlockMode::ReadExclusiveLockBh`]
80//! + 关闭全局中断的模式: [`SeqlockMode::WriteLockCpuirq`] 以及 [`SeqlockMode::ReadExclusiveLockCpuirq`]
81//! + 保存中断全局标志并关闭全局中断的模式: [`SeqlockMode::WriteLockCpuirqSave(None)`] 以及 [`SeqlockMode::ReadExclusiveLockCpuirqSave(None)`]
82//!
83//!
84//! # 尝试上锁
85//!
86//! 尝试上锁的方法 [`Seqlock::trylock()`] 只会测试一下锁,不会 **自旋** 等待,上锁成功后还会根据上锁模式增加额外操作:
87//!
88//! + 只关闭抢占的模式: [`SeqlockMode::WriteLock`] 以及 [`SeqlockMode::ReadExclusiveLock`]
89//! + 关闭中断底半部的模式: [`SeqlockMode::WriteLockBh`] 以及 [`SeqlockMode::ReadExclusiveLockBh`]
90//! + 关闭全局中断的模式: [`SeqlockMode::WriteLockCpuirq`] 以及 [`SeqlockMode::ReadExclusiveLockCpuirq`]
91//! + 保存中断全局标志并关闭全局中断的模式: [`SeqlockMode::WriteLockCpuirqSave(None)`] 以及 [`SeqlockMode::ReadExclusiveLockCpuirqSave(None)`]
92//!
93//!
94//! # 示例
95//!
96//! [XWOS/xwam/xwrust-example/xwrust_example_seqlock](https://gitee.com/xwos/XWOS/blob/main/xwam/xwrust-example/xwrust_example_seqlock/src/lib.rs)
97//!
98//! [`SeqlockMode::WriteLockCpuirqSave(None)`]: SeqlockMode::WriteLockCpuirqSave
99//! [`SeqlockMode::ReadExclusiveLockCpuirqSave(None)`]: SeqlockMode::ReadExclusiveLockCpuirqSave
100//! [`static`]: https://doc.rust-lang.org/std/keyword.static.html
101//! [`alloc::sync::Arc`]: <https://doc.rust-lang.org/alloc/sync/struct.Arc.html>
102
103extern crate core;
104use core::cell::UnsafeCell;
105use core::result::Result;
106use core::default::Default;
107use core::option::Option;
108use core::ops::Drop;
109use core::ops::Deref;
110use core::ops::DerefMut;
111use core::ptr;
112
113use crate::types::*;
114use crate::errno::*;
115
116use crate::xwos::sync::cond::*;
117
118extern "C" {
119    fn xwrustffi_sqlk_init(sqlk: *mut XwosSqlk);
120
121    fn xwrustffi_sqlk_rd_begin(sqlk: *mut XwosSqlk) -> XwSq;
122    fn xwrustffi_sqlk_rd_retry(sqlk: *mut XwosSqlk, start: XwSq) -> bool;
123
124    fn xwrustffi_sqlk_rdex_unlock(sqlk: *mut XwosSqlk);
125    fn xwrustffi_sqlk_rdex_lock(sqlk: *mut XwosSqlk);
126    fn xwrustffi_sqlk_rdex_trylock(sqlk: *mut XwosSqlk) -> XwEr;
127    fn xwrustffi_sqlk_rdex_unlock_cpuirq(sqlk: *mut XwosSqlk);
128    fn xwrustffi_sqlk_rdex_lock_cpuirq(sqlk: *mut XwosSqlk);
129    fn xwrustffi_sqlk_rdex_trylock_cpuirq(sqlk: *mut XwosSqlk) -> XwEr;
130    fn xwrustffi_sqlk_rdex_unlock_cpuirqrs(sqlk: *mut XwosSqlk, cpuirq: XwReg);
131    fn xwrustffi_sqlk_rdex_lock_cpuirqsv(sqlk: *mut XwosSqlk, cpuirq: *mut XwReg);
132    fn xwrustffi_sqlk_rdex_trylock_cpuirqsv(sqlk: *mut XwosSqlk, cpuirq: *mut XwReg) -> XwEr;
133    fn xwrustffi_sqlk_rdex_unlock_bh(sqlk: *mut XwosSqlk);
134    fn xwrustffi_sqlk_rdex_lock_bh(sqlk: *mut XwosSqlk);
135    fn xwrustffi_sqlk_rdex_trylock_bh(sqlk: *mut XwosSqlk) -> XwEr;
136
137    fn xwrustffi_sqlk_wr_unlock(sqlk: *mut XwosSqlk);
138    fn xwrustffi_sqlk_wr_lock(sqlk: *mut XwosSqlk);
139    fn xwrustffi_sqlk_wr_trylock(sqlk: *mut XwosSqlk) -> XwEr;
140    fn xwrustffi_sqlk_wr_unlock_cpuirq(sqlk: *mut XwosSqlk);
141    fn xwrustffi_sqlk_wr_lock_cpuirq(sqlk: *mut XwosSqlk);
142    fn xwrustffi_sqlk_wr_trylock_cpuirq(sqlk: *mut XwosSqlk) -> XwEr;
143    fn xwrustffi_sqlk_wr_unlock_cpuirqrs(sqlk: *mut XwosSqlk, cpuirq: XwReg);
144    fn xwrustffi_sqlk_wr_lock_cpuirqsv(sqlk: *mut XwosSqlk, cpuirq: *mut XwReg);
145    fn xwrustffi_sqlk_wr_trylock_cpuirqsv(sqlk: *mut XwosSqlk, cpuirq: *mut XwReg) -> XwEr;
146    fn xwrustffi_sqlk_wr_unlock_bh(sqlk: *mut XwosSqlk);
147    fn xwrustffi_sqlk_wr_lock_bh(sqlk: *mut XwosSqlk);
148    fn xwrustffi_sqlk_wr_trylock_bh(sqlk: *mut XwosSqlk) -> XwEr;
149}
150
151/// 顺序锁的错误码
152#[derive(Debug)]
153pub enum SeqlockError {
154    /// 尝试上锁失败
155    Again(XwEr),
156    /// 未知错误
157    Unknown(XwEr),
158}
159
160impl SeqlockError {
161    /// 消费掉 `SeqlockError` 自身,返回内部的错误码。
162    pub fn unwrap(self) -> XwEr {
163        match self {
164            Self::Again(rc) => rc,
165            Self::Unknown(rc) => rc,
166        }
167    }
168}
169
170/// 顺序锁的上锁模式
171pub enum SeqlockMode {
172    /// 写,关闭抢占
173    WriteLock,
174    /// 写,关闭抢占、中断底半部
175    WriteLockBh,
176    /// 写,关闭抢占、中断底半部和中断
177    WriteLockCpuirq,
178    /// 写,关闭抢占、中断底半部和中断,并保存之前的中断标志
179    WriteLockCpuirqSave(Option<XwReg>),
180    /// 独占读,关闭抢占
181    ReadExclusiveLock,
182    /// 独占读,关闭抢占、中断底半部
183    ReadExclusiveLockBh,
184    /// 独占读,关闭抢占、中断底半部和中断
185    ReadExclusiveLockCpuirq,
186    /// 独占读,关闭抢占、中断底半部和中断,并保存之前的中断标志
187    ReadExclusiveLockCpuirqSave(Option<XwReg>),
188}
189
190/// XWOS顺序锁占用的内存大小
191#[cfg(target_pointer_width = "32")]
192pub const SIZEOF_XWOS_SQLK: usize = 8;
193
194/// XWOS顺序锁占用的内存大小
195#[cfg(target_pointer_width = "64")]
196pub const SIZEOF_XWOS_SQLK: usize = 16;
197
198/// 用于构建顺序锁的内存数组类型
199#[repr(C)]
200#[cfg_attr(target_pointer_width = "32", repr(align(8)))]
201#[cfg_attr(target_pointer_width = "64", repr(align(16)))]
202pub(crate) struct XwosSqlk {
203    pub(crate) obj: [u8; SIZEOF_XWOS_SQLK],
204}
205
206/// 用于构建顺序锁的内存数组常量
207///
208/// 此常量的作用是告诉编译器顺序锁需要多大的内存。
209pub(crate) const XWOS_SQLK_INITIALIZER: XwosSqlk = XwosSqlk {
210    obj: [0; SIZEOF_XWOS_SQLK],
211};
212
213
214/// 顺序锁结构体
215pub struct Seqlock<T: ?Sized> {
216    /// XWOS顺序锁
217    pub(crate) sqlk: UnsafeCell<XwosSqlk>,
218    /// 上锁方式
219    pub(crate) mode: UnsafeCell<SeqlockMode>,
220    /// 用户数据
221    pub data: UnsafeCell<T>,
222}
223
224impl<T> Seqlock<T> {
225    /// 新建顺序锁
226    ///
227    /// 此方法是编译期方法,可用于新建 [`static`] 约束的全局变量。
228    ///
229    /// # 示例
230    ///
231    /// ```rust
232    /// use xwrust::xwos::lock::seqlock::*;
233    ///
234    /// static GLOBAL_SEQLOCK: Seqlock<u32>  = Seqlock::new(0);
235    /// ```
236    ///
237    /// [`static`]: https://doc.rust-lang.org/std/keyword.static.html
238    pub const fn new(t: T) -> Self {
239        Self {
240            sqlk: UnsafeCell::new(XWOS_SQLK_INITIALIZER),
241            mode: UnsafeCell::new(SeqlockMode::WriteLock),
242            data: UnsafeCell::new(t),
243        }
244    }
245}
246
247impl<T: ?Sized> Seqlock<T> {
248    /// 开启共享读临界区
249    ///
250    /// 若其他CPU正在访问写临界区,此方法会一直 **自旋** 测试是否可进入 **共享读临界区** 。
251    ///
252    /// # 示例
253    ///
254    /// ```rust
255    /// loop {
256    ///     let guard = sqlk.read_begin();
257    ///     let val = *guard; // 读取
258    ///     if !guard.read_retry() {
259    ///         break;
260    ///     }
261    /// }
262    /// ```
263    pub fn read_begin(&self) -> SeqlockReadGuard<'_, T> {
264        unsafe {
265            let start = xwrustffi_sqlk_rd_begin(self.sqlk.get());
266            SeqlockReadGuard::new(self, start)
267        }
268    }
269
270    fn read_retry(&self, start: XwSq) -> bool {
271        unsafe {
272            xwrustffi_sqlk_rd_retry(self.sqlk.get(), start)
273        }
274    }
275
276    /// 获取顺序锁,若线程无法获取顺序锁,就阻塞等待,直到能获得锁为止
277    ///
278    /// + 若成功获取顺序锁,将返回 **RAII Guard** : [`SeqlockGuard`] ,用于提供 **Scoped Lock** 机制。
279    ///   + [`SeqlockGuard`] 中包含 [`Seqlock`] 的引用, 当 [`SeqlockGuard`] 生命周期结束时,会在 [`drop()`] 方法中自动解锁顺序锁。
280    /// + 若失败,将返回错误码 [`SeqlockError`] 。
281    ///
282    /// # 参数说明
283    ///
284    /// + mode: 锁模式
285    ///   + [`SeqlockMode::WriteLock`] 写,关闭抢占
286    ///   + [`SeqlockMode::WriteLockBh`] 写,关闭抢占、中断底半部
287    ///   + [`SeqlockMode::WriteLockCpuirq`] 写,关闭抢占、中断底半部和中断
288    ///   + [`SeqlockMode::WriteLockCpuirqSave(None)`] 写,关闭抢占、中断底半部和中断,并保存之前的中断标志
289    ///   + [`SeqlockMode::ReadExclusiveLock`] 独占读,关闭抢占
290    ///   + [`SeqlockMode::ReadExclusiveLockBh`] 独占读,关闭抢占、中断底半部
291    ///   + [`SeqlockMode::ReadExclusiveLockCpuirq`] 独占读,关闭抢占、中断底半部和中断
292    ///   + [`SeqlockMode::ReadExclusiveLockCpuirqSave(None)`] 独占读,关闭抢占、中断底半部和中断,并保存之前的中断标志
293    ///
294    /// # 示例
295    ///
296    /// ```rust
297    /// use xwrust::xwos::lock::seqlock::*;
298    /// static GLOBAL_SEQLOCK: Seqlock<u32> = Seqlock::new(0);
299    ///
300    /// pub fn xwrust_example_seqlock() {
301    ///     // ...省略...
302    ///     let mut guard GLOBAL_SEQLOCK.lock(SeqlockMode::ReadExclusiveLockCpuirqSave(None));
303    ///     *guard = 1; // 写共享变量
304    ///     drop(guard); // guard 生命周期结束,自动解锁,并恢复中断标志
305    /// }
306    /// ```
307    ///
308    /// [`SeqlockMode::WriteLockCpuirqSave(None)`]: SeqlockMode::WriteLockCpuirqSave
309    /// [`SeqlockMode::ReadExclusiveLockCpuirqSave(None)`]: SeqlockMode::ReadExclusiveLockCpuirqSave
310    /// [`drop()`]: https://doc.rust-lang.org/std/mem/fn.drop.html
311    pub fn lock(&self, mode: SeqlockMode) -> SeqlockGuard<'_, T> {
312        unsafe {
313            match mode {
314                SeqlockMode::ReadExclusiveLock => {
315                    xwrustffi_sqlk_rdex_lock(self.sqlk.get());
316                    *self.mode.get() = SeqlockMode::ReadExclusiveLock;
317                },
318                SeqlockMode::ReadExclusiveLockCpuirq => {
319                    xwrustffi_sqlk_rdex_lock_cpuirq(self.sqlk.get());
320                    *self.mode.get() = SeqlockMode::ReadExclusiveLockCpuirq;
321                },
322                SeqlockMode::ReadExclusiveLockCpuirqSave(_) => {
323                    let mut cpuirq: XwReg = 0;
324                    xwrustffi_sqlk_rdex_lock_cpuirqsv(self.sqlk.get(), &mut cpuirq);
325                    *self.mode.get() = SeqlockMode::ReadExclusiveLockCpuirqSave(Some(cpuirq));
326                },
327                SeqlockMode::ReadExclusiveLockBh => {
328                    xwrustffi_sqlk_rdex_lock_bh(self.sqlk.get());
329                    *self.mode.get() = SeqlockMode::ReadExclusiveLockBh;
330                },
331
332
333                SeqlockMode::WriteLock => {
334                    xwrustffi_sqlk_wr_lock(self.sqlk.get());
335                    *self.mode.get() = SeqlockMode::WriteLock;
336                },
337                SeqlockMode::WriteLockCpuirq => {
338                    xwrustffi_sqlk_wr_lock_cpuirq(self.sqlk.get());
339                    *self.mode.get() = SeqlockMode::WriteLockCpuirq;
340                },
341                SeqlockMode::WriteLockCpuirqSave(_) => {
342                    let mut cpuirq: XwReg = 0;
343                    xwrustffi_sqlk_wr_lock_cpuirqsv(self.sqlk.get(), &mut cpuirq);
344                    *self.mode.get() = SeqlockMode::WriteLockCpuirqSave(Some(cpuirq));
345                },
346                SeqlockMode::WriteLockBh => {
347                    xwrustffi_sqlk_wr_lock_bh(self.sqlk.get());
348                    *self.mode.get() = SeqlockMode::WriteLockBh;
349                },
350            }
351            SeqlockGuard::new(self)
352        }
353    }
354
355    /// 尝试获取顺序锁,若线程无法获取顺序锁,立即返回错误
356    ///
357    /// + 若成功获取顺序锁,将返回 **RAII Guard** : [`SeqlockGuard`] ,用于提供 **Scoped Lock** 机制。
358    ///   + [`SeqlockGuard`] 中包含 [`Seqlock`] 的引用, 当 [`SeqlockGuard`] 生命周期结束时,会在 [`drop()`] 方法中自动解锁顺序锁。
359    /// + 若失败,将返回错误码 [`SeqlockError`] 。
360    ///
361    ///
362    /// # 参数说明
363    ///
364    /// + mode: 锁模式
365    ///   + [`SeqlockMode::WriteLock`] 写,关闭抢占
366    ///   + [`SeqlockMode::WriteLockBh`] 写,关闭抢占、中断底半部
367    ///   + [`SeqlockMode::WriteLockCpuirq`] 写,关闭抢占、中断底半部和中断
368    ///   + [`SeqlockMode::WriteLockCpuirqSave(None)`] 写,关闭抢占、中断底半部和中断,并保存之前的中断标志
369    ///   + [`SeqlockMode::ReadExclusiveLock`] 独占读,关闭抢占
370    ///   + [`SeqlockMode::ReadExclusiveLockBh`] 独占读,关闭抢占、中断底半部
371    ///   + [`SeqlockMode::ReadExclusiveLockCpuirq`] 独占读,关闭抢占、中断底半部和中断
372    ///   + [`SeqlockMode::ReadExclusiveLockCpuirqSave(None)`] 独占读,关闭抢占、中断底半部和中断,并保存之前的中断标志
373    ///
374    /// # 错误码
375    ///
376    /// + [`SeqlockError::Again`] 尝试获取锁失败
377    ///
378    /// # 示例
379    /// ```rust
380    /// use xwrust::xwos::lock::seqlock::*;
381    /// static GLOBAL_SEQLOCK: Seqlock<u32> = Seqlock::new(0);
382    ///
383    /// pub fn xwrust_example_seqlock() {
384    ///     // ...省略...
385    ///     match GLOBAL_SEQLOCK.trylock(SeqlockMode::ReadExclusiveLockCpuirq) {
386    ///         Ok(mut guard) => { // 上锁成功
387    ///             *guard = 1; // 写共享变量
388    ///         } // guard 生命周期结束,自动解锁
389    ///         Err(e) => {
390    ///             // 上锁失败
391    ///         }
392    ///     }
393    /// }
394    /// ```
395    ///
396    /// [`SeqlockMode::WriteLockCpuirqSave(None)`]: SeqlockMode::WriteLockCpuirqSave
397    /// [`SeqlockMode::ReadExclusiveLockCpuirqSave(None)`]: SeqlockMode::ReadExclusiveLockCpuirqSave
398    /// [`drop()`]: https://doc.rust-lang.org/std/mem/fn.drop.html
399    pub fn trylock(&self, mode: SeqlockMode) -> Result<SeqlockGuard<'_, T>, SeqlockError> {
400        unsafe {
401            let rc: XwEr;
402            match mode {
403                SeqlockMode::ReadExclusiveLock => {
404                    rc = xwrustffi_sqlk_rdex_trylock(self.sqlk.get());
405                    if 0 == rc {
406                        *self.mode.get() = SeqlockMode::ReadExclusiveLock;
407                        Ok(SeqlockGuard::new(self))
408                    } else if -EAGAIN == rc {
409                        Err(SeqlockError::Again(rc))
410                    } else {
411                        Err(SeqlockError::Unknown(rc))
412                    }
413                },
414                SeqlockMode::ReadExclusiveLockCpuirq => {
415                    rc = xwrustffi_sqlk_rdex_trylock_cpuirq(self.sqlk.get());
416                    if 0 == rc {
417                        *self.mode.get() = SeqlockMode::ReadExclusiveLockCpuirq;
418                        Ok(SeqlockGuard::new(self))
419                    } else if -EAGAIN == rc {
420                        Err(SeqlockError::Again(rc))
421                    } else {
422                        Err(SeqlockError::Unknown(rc))
423                    }
424                },
425                SeqlockMode::ReadExclusiveLockCpuirqSave(_) => {
426                    let mut cpuirq: XwReg = 0;
427                    rc = xwrustffi_sqlk_rdex_trylock_cpuirqsv(self.sqlk.get(), &mut cpuirq);
428                    if 0 == rc {
429                        *self.mode.get() = SeqlockMode::ReadExclusiveLockCpuirqSave(Some(cpuirq));
430                        Ok(SeqlockGuard::new(self))
431                    } else if -EAGAIN == rc {
432                        Err(SeqlockError::Again(rc))
433                    } else {
434                        Err(SeqlockError::Unknown(rc))
435                    }
436                },
437                SeqlockMode::ReadExclusiveLockBh => {
438                    rc = xwrustffi_sqlk_rdex_trylock_bh(self.sqlk.get());
439                    if 0 == rc {
440                        *self.mode.get() = SeqlockMode::ReadExclusiveLockBh;
441                        Ok(SeqlockGuard::new(self))
442                    } else if -EAGAIN == rc {
443                        Err(SeqlockError::Again(rc))
444                    } else {
445                        Err(SeqlockError::Unknown(rc))
446                    }
447                },
448
449                SeqlockMode::WriteLock => {
450                    rc = xwrustffi_sqlk_wr_trylock(self.sqlk.get());
451                    if 0 == rc {
452                        *self.mode.get() = SeqlockMode::WriteLock;
453                        Ok(SeqlockGuard::new(self))
454                    } else if -EAGAIN == rc {
455                        Err(SeqlockError::Again(rc))
456                    } else {
457                        Err(SeqlockError::Unknown(rc))
458                    }
459                },
460                SeqlockMode::WriteLockCpuirq => {
461                    rc = xwrustffi_sqlk_wr_trylock_cpuirq(self.sqlk.get());
462                    if 0 == rc {
463                        *self.mode.get() = SeqlockMode::WriteLockCpuirq;
464                        Ok(SeqlockGuard::new(self))
465                    } else if -EAGAIN == rc {
466                        Err(SeqlockError::Again(rc))
467                    } else {
468                        Err(SeqlockError::Unknown(rc))
469                    }
470                },
471                SeqlockMode::WriteLockCpuirqSave(_) => {
472                    let mut cpuirq: XwReg = 0;
473                    rc = xwrustffi_sqlk_wr_trylock_cpuirqsv(self.sqlk.get(), &mut cpuirq);
474                    if 0 == rc {
475                        *self.mode.get() = SeqlockMode::WriteLockCpuirqSave(Some(cpuirq));
476                        Ok(SeqlockGuard::new(self))
477                    } else if -EAGAIN == rc {
478                        Err(SeqlockError::Again(rc))
479                    } else {
480                        Err(SeqlockError::Unknown(rc))
481                    }
482                },
483                SeqlockMode::WriteLockBh => {
484                    rc = xwrustffi_sqlk_wr_trylock_bh(self.sqlk.get());
485                    if 0 == rc {
486                        *self.mode.get() = SeqlockMode::WriteLockBh;
487                        Ok(SeqlockGuard::new(self))
488                    } else if -EAGAIN == rc {
489                        Err(SeqlockError::Again(rc))
490                    } else {
491                        Err(SeqlockError::Unknown(rc))
492                    }
493                },
494            }
495        }
496    }
497
498    /// 解锁顺序锁,并释放 [`SeqlockGuard`]
499    ///
500    /// # 示例
501    ///
502    /// ```rust
503    /// use xwrust::xwos::lock::seqlock::*;
504    /// static GLOBAL_SEQLOCK: Seqlock<u32> = Seqlock::new(0);
505    ///
506    /// pub fn xwrust_example_seqlock() {
507    ///     // ...省略...
508    ///     match GLOBAL_SEQLOCK.lock() {
509    ///         Ok(mut guard) => { // 上锁成功
510    ///             *guard = 1; // 访问共享变量
511    ///             Seqlock::unlock(guard); // 主动解锁
512    ///         }
513    ///         Err(e) => {
514    ///             // 上锁失败
515    ///         }
516    ///     }
517    /// }
518    /// ```
519    ///
520    /// [`drop()`]: https://doc.rust-lang.org/std/mem/fn.drop.html
521    pub fn unlock(guard: SeqlockGuard<'_, T>) {
522        drop(guard)
523    }
524}
525
526unsafe impl<T: ?Sized + Send> Send for Seqlock<T> {}
527unsafe impl<T: ?Sized + Send> Sync for Seqlock<T> {}
528
529impl<T> From<T> for Seqlock<T> {
530    /// 从数据新建顺序锁
531    ///
532    /// 此方法会将数据所有权转移到顺序锁的内部
533    ///
534    /// 等价于 [`Seqlock::new`]
535    fn from(t: T) -> Self {
536        Seqlock::new(t)
537    }
538}
539
540impl<T: ?Sized + Default> Default for Seqlock<T> {
541    fn default() -> Seqlock<T> {
542        Seqlock::new(Default::default())
543    }
544}
545
546impl<T: ?Sized> Drop for Seqlock<T> {
547    fn drop(&mut self) {
548    }
549}
550
551/// 顺序锁共享读临界区的守卫
552///
553/// 共享读临界区的守卫只提供解引用到只读引用。
554///
555pub struct SeqlockReadGuard<'a, T: ?Sized + 'a> {
556    /// 顺序锁的引用
557    lock: &'a Seqlock<T>,
558    start: XwSq,
559}
560
561impl<T: ?Sized> !Send for SeqlockReadGuard<'_, T> {}
562unsafe impl<T: ?Sized + Sync> Sync for SeqlockReadGuard<'_, T> {}
563
564impl<'a, T: ?Sized> SeqlockReadGuard<'a, T> {
565    fn new(lock: &'a Seqlock<T>, start: XwSq) -> SeqlockReadGuard<'a, T> {
566        SeqlockReadGuard {
567            lock: lock,
568            start: start,
569        }
570    }
571
572    /// 关闭共享读临界区,并检查是否需要重试
573    ///
574    /// + 当顺序锁的顺序值没有发生变化,返回 [`false`] ;
575    /// + 当顺序锁的顺序值发生了变化,返回 [`true`] 。
576    ///
577    /// # 示例
578    ///
579    /// ```rust
580    /// loop {
581    ///     let guard = sqlk.read_begin();
582    ///     let val = *guard;
583    ///     if !guard.read_retry() {
584    ///         break;
585    ///     }
586    /// }
587    /// ```
588    pub fn read_retry(&self) -> bool {
589        self.lock.read_retry(self.start)
590    }
591}
592
593impl<T: ?Sized> Deref for SeqlockReadGuard<'_, T> {
594    type Target = T;
595
596    fn deref(&self) -> &T {
597        unsafe { &*self.lock.data.get() }
598    }
599}
600
601/// 顺序锁的RAII Guard
602///
603/// **RAII Guard** 用于提供 **Scoped Lock** 机制。
604///
605/// + [`SeqlockGuard`] 中包含 [`Seqlock`] 的引用, 当 [`SeqlockGuard`] 生命周期结束时,会在 [`drop()`] 方法中自动解锁顺序锁。
606/// + [`SeqlockGuard`] 不可在线程之间转移所有权,因为其 [`drop()`] 方法包含解锁的语义,上锁和解锁必须在同一线程;
607/// + [`SeqlockGuard`] 虽然可以在多线程中传递引用( [`Sync`] 约束),但其实现中没有 **unlock()** 方法,意味着其他线程即便拿到引用也不能解锁。
608///
609/// [`drop()`]: https://doc.rust-lang.org/std/mem/fn.drop.html
610/// [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Send.html
611pub struct SeqlockGuard<'a, T: ?Sized + 'a> {
612    /// 顺序锁的引用
613    lock: &'a Seqlock<T>,
614}
615
616impl<T: ?Sized> !Send for SeqlockGuard<'_, T> {}
617unsafe impl<T: ?Sized + Sync> Sync for SeqlockGuard<'_, T> {}
618
619impl<'a, T: ?Sized> SeqlockGuard<'a, T> {
620    fn new(lock: &'a Seqlock<T>) -> SeqlockGuard<'a, T> {
621        SeqlockGuard { lock: lock }
622    }
623
624    fn lock(&self) {
625        unsafe {
626            let mode = &*self.lock.mode.get();
627            match mode {
628                SeqlockMode::WriteLock |
629                SeqlockMode::WriteLockBh |
630                SeqlockMode::WriteLockCpuirq |
631                SeqlockMode::WriteLockCpuirqSave(_) => {
632                    xwrustffi_sqlk_wr_lock(self.lock.sqlk.get());
633                },
634                SeqlockMode::ReadExclusiveLock |
635                SeqlockMode::ReadExclusiveLockBh |
636                SeqlockMode::ReadExclusiveLockCpuirq |
637                SeqlockMode::ReadExclusiveLockCpuirqSave(_) => {
638                    xwrustffi_sqlk_rdex_lock(self.lock.sqlk.get());
639                },
640            }
641        }
642    }
643
644    fn unlock(&self) {
645        unsafe {
646            let mode = &*self.lock.mode.get();
647            match mode {
648                SeqlockMode::WriteLock |
649                SeqlockMode::WriteLockBh |
650                SeqlockMode::WriteLockCpuirq |
651                SeqlockMode::WriteLockCpuirqSave(_) => {
652                    xwrustffi_sqlk_wr_unlock(self.lock.sqlk.get());
653                },
654                SeqlockMode::ReadExclusiveLock |
655                SeqlockMode::ReadExclusiveLockBh |
656                SeqlockMode::ReadExclusiveLockCpuirq |
657                SeqlockMode::ReadExclusiveLockCpuirqSave(_) => {
658                    xwrustffi_sqlk_rdex_unlock(self.lock.sqlk.get());
659                },
660            }
661        }
662    }
663
664    /// 阻塞当前线程,直到被条件量唤醒
665    ///
666    /// 此方法会消费顺序锁的守卫(Guard),并当线程阻塞时,在条件量内部释放顺序锁。
667    /// 当条件成立,线程被唤醒,会在条件量内部上锁顺序锁,并重新返回顺序锁的守卫(Guard)。
668    ///
669    /// + 当返回顺序锁的守卫 [`SeqlockGuard`] 时,顺序锁已经被重新上锁;
670    /// + 当返回 [`Err`] 时,顺序锁未被上锁。
671    ///
672    /// # 参数说明
673    ///
674    /// + cond: 条件量的引用
675    ///
676    /// # 错误码
677    ///
678    /// + [`CondError::NotInit`] 条件量未被初始化
679    /// + [`CondError::Interrupt`] 等待被中断
680    /// + [`CondError::NotThreadContext`] 不在线程上下文中
681    ///
682    /// # 示例
683    ///
684    /// ```rust
685    /// use xwrust::xwos::thd;
686    /// use xwrust::xwos::lock::seqlock::*;
687    /// use xwrust::xwos::sync::cond::*;
688    /// extern crate alloc;
689    /// use alloc::sync::Arc;
690    ///
691    /// pub fn xwrust_example_seqlock() {
692    ///     let pair = Arc::new((Seqlock::new(true), Cond::new()));
693    ///     pair.1.init();
694    ///     let pair_c = pair.clone();
695    ///
696    ///     thd::Builder::new()
697    ///         .name("child".into())
698    ///         .spawn(move |_| { // 子线程闭包
699    ///             cthd::sleep(xwtm::ms(500));
700    ///             let (lock, cvar) = &*pair_c;
701    ///             let mut guard = lock_child.lock(SeqlockMode::WriteLockCpuirqSave(None));
702    ///             *guard = false; // 设置共享数据
703    ///             drop(guard); // 先解锁再触发条件可提高效率
704    ///             cvar.broadcast();
705    ///         });
706    ///     let (lock, cvar) = &*pair;
707    ///     {
708    ///         let mut guard = lock.lock(SeqlockMode::WriteLockCpuirqSave(None));
709    ///         while *guard {
710    ///             match guard.wait(cvar) {
711    ///                 Ok(g) => { // 唤醒
712    ///                     guard = g;
713    ///                 },
714    ///                 Err(e) => { // 等待条件量失败
715    ///                     break;
716    ///                 },
717    ///             }
718    ///         }
719    ///     }
720    /// }
721    /// ```
722    ///
723    /// [`Err`]: <https://doc.rust-lang.org/core/result/enum.Result.html#variant.Err>
724    pub fn wait(self, cond: &Cond) -> Result<SeqlockGuard<'a, T>, CondError> {
725        unsafe {
726            let mut rc = xwrustffi_cond_acquire(cond.cond.get(), *cond.tik.get());
727            if rc == 0 {
728                let lktype = match &*self.lock.mode.get() {
729                    SeqlockMode::WriteLock |
730                    SeqlockMode::WriteLockBh |
731                    SeqlockMode::WriteLockCpuirq |
732                    SeqlockMode::WriteLockCpuirqSave(_) => {
733                        XWOS_LK_SQLK_WR
734                    },
735                    SeqlockMode::ReadExclusiveLock |
736                    SeqlockMode::ReadExclusiveLockBh |
737                    SeqlockMode::ReadExclusiveLockCpuirq |
738                    SeqlockMode::ReadExclusiveLockCpuirqSave(_) => {
739                        XWOS_LK_SQLK_RDEX
740                    },
741                };
742                let mut lkst = 0;
743                rc = xwrustffi_cond_wait(cond.cond.get(),
744                                         self.lock.sqlk.get() as _, lktype, ptr::null_mut(),
745                                         &mut lkst);
746                xwrustffi_cond_put(cond.cond.get());
747                if 0 == rc {
748                    Ok(self)
749                } else {
750                    if XWOS_LKST_LOCKED == lkst {
751                        drop(self);
752                    } else {
753                        self.lock();
754                        drop(self);
755                    }
756                    if -EINTR == rc {
757                        Err(CondError::Interrupt(rc))
758                    } else if -ENOTTHDCTX == rc {
759                        Err(CondError::NotThreadContext(rc))
760                    } else {
761                        Err(CondError::Unknown(rc))
762                    }
763                }
764            } else {
765                drop(self);
766                Err(CondError::NotInit(rc))
767            }
768        }
769    }
770
771    /// 限时阻塞当前线程,直到被条件量唤醒
772    ///
773    /// 此方法会消费顺序锁的守卫(Guard),并当线程阻塞时,在条件量内部释放顺序锁。
774    /// 当条件成立,线程被唤醒,会在条件量内部上锁顺序锁,并重新返回顺序锁的守卫(Guard)。
775    /// 当超时后,将返回错误。
776    ///
777    /// + 当返回顺序锁的守卫 [`SeqlockGuard`] 时,顺序锁已经被重新上锁;
778    /// + 当返回 [`Err`] 时,顺序锁未被上锁。
779    ///
780    /// # 参数说明
781    ///
782    /// + cond: 条件量的引用
783    /// + to: 期望唤醒的时间点
784    ///
785    /// # 错误码
786    ///
787    /// + [`CondError::NotInit`] 条件量未被初始化
788    /// + [`CondError::Interrupt`] 等待被中断
789    /// + [`CondError::Timedout`] 等待超时
790    /// + [`CondError::NotThreadContext`] 不在线程上下文中
791    ///
792    /// # 示例
793    ///
794    /// ```rust
795    /// use xwrust::xwos::thd;
796    /// use xwrust::xwos::lock::seqlock::*;
797    /// use xwrust::xwos::sync::cond::*;
798    /// extern crate alloc;
799    /// use alloc::sync::Arc;
800    ///
801    /// pub fn xwrust_example_seqlock() {
802    ///     let pair = Arc::new((Seqlock::new(true), Cond::new()));
803    ///     pair.1.init();
804    ///     let pair_c = pair.clone();
805    ///
806    ///     thd::Builder::new()
807    ///         .name("child".into())
808    ///         .spawn(move |_| { // 子线程闭包
809    ///             cthd::sleep(xwtm::ms(500));
810    ///             let (lock, cvar) = &*pair_c;
811    ///             let mut guard = lock_child.lock(SeqlockMode::WriteLockCpuirqSave(None));
812    ///             *guard = false; // 设置共享数据
813    ///             drop(guard); // 先解锁再触发条件可提高效率
814    ///             cvar.broadcast();
815    ///         });
816    ///     let (lock, cvar) = &*pair;
817    ///     {
818    ///         let mut guard = lock.lock(SeqlockMode::WriteLockCpuirqSave(None));
819    ///         while *guard {
820    ///             match guard.wait_to(cvar, xwtm::ft(xwtm::s(2))) {
821    ///                 Ok(g) => { // 唤醒
822    ///                     guard = g;
823    ///                 },
824    ///                 Err(e) => { // 等待条件量失败
825    ///                     break;
826    ///                 },
827    ///             }
828    ///         }
829    ///     }
830    /// }
831    /// ```
832    ///
833    /// [`Err`]: <https://doc.rust-lang.org/core/result/enum.Result.html#variant.Err>
834    pub fn wait_to(self, cond: &Cond, to: XwTm) -> Result<SeqlockGuard<'a, T>, CondError> {
835        unsafe {
836            let mut rc = xwrustffi_cond_acquire(cond.cond.get(), *cond.tik.get());
837            if rc == 0 {
838                let lktype = match &*self.lock.mode.get() {
839                    SeqlockMode::WriteLock |
840                    SeqlockMode::WriteLockBh |
841                    SeqlockMode::WriteLockCpuirq |
842                    SeqlockMode::WriteLockCpuirqSave(_) => {
843                        XWOS_LK_SQLK_WR
844                    },
845                    SeqlockMode::ReadExclusiveLock |
846                    SeqlockMode::ReadExclusiveLockBh |
847                    SeqlockMode::ReadExclusiveLockCpuirq |
848                    SeqlockMode::ReadExclusiveLockCpuirqSave(_) => {
849                        XWOS_LK_SQLK_RDEX
850                    },
851                };
852                let mut lkst = 0;
853                rc = xwrustffi_cond_wait_to(cond.cond.get(),
854                                            self.lock.sqlk.get() as _, lktype, ptr::null_mut(),
855                                            to, &mut lkst);
856                xwrustffi_cond_put(cond.cond.get());
857                if 0 == rc {
858                    Ok(self)
859                } else {
860                    if XWOS_LKST_LOCKED == lkst {
861                        drop(self);
862                    } else {
863                        self.lock();
864                        drop(self);
865                    }
866                    if -EINTR == rc {
867                        Err(CondError::Interrupt(rc))
868                    } else if -ETIMEDOUT == rc {
869                        Err(CondError::Timedout(rc))
870                    } else if -ENOTTHDCTX == rc {
871                        Err(CondError::NotThreadContext(rc))
872                    } else {
873                        Err(CondError::Unknown(rc))
874                    }
875                }
876            } else {
877                drop(self);
878                Err(CondError::NotInit(rc))
879            }
880        }
881    }
882
883    /// 阻塞当前线程,直到被条件量唤醒,且阻塞不可被中断
884    ///
885    /// 此方法会消费顺序锁的守卫(Guard),并当线程阻塞时,在条件量内部释放顺序锁。
886    /// 当条件成立,线程被唤醒,会在条件量内部上锁顺序锁,并重新返回顺序锁的守卫(Guard)。
887    ///
888    /// + 当返回顺序锁的守卫 [`SeqlockGuard`] 时,顺序锁已经被重新上锁;
889    /// + 当返回 [`Err`] 时,顺序锁未被上锁。
890    ///
891    /// # 参数说明
892    ///
893    /// + cond: 条件量的引用
894    ///
895    /// # 错误码
896    ///
897    /// + [`CondError::NotInit`] 条件量未被初始化
898    /// + [`CondError::NotThreadContext`] 不在线程上下文中
899    ///
900    /// # 示例
901    ///
902    /// ```rust
903    /// use xwrust::xwos::thd;
904    /// use xwrust::xwos::lock::seqlock::*;
905    /// use xwrust::xwos::sync::cond::*;
906    /// extern crate alloc;
907    /// use alloc::sync::Arc;
908    ///
909    /// pub fn xwrust_example_seqlock() {
910    ///     let pair = Arc::new((Seqlock::new(true), Cond::new()));
911    ///     pair.1.init();
912    ///     let pair_c = pair.clone();
913    ///
914    ///     thd::Builder::new()
915    ///         .name("child".into())
916    ///         .spawn(move |_| { // 子线程闭包
917    ///             cthd::sleep(xwtm::ms(500));
918    ///             let (lock, cvar) = &*pair_c;
919    ///             let mut guard = lock_child.lock(SeqlockMode::ReadExclusiveLockCpuirqSave(None));
920    ///             *guard = false; // 设置共享数据
921    ///             drop(guard); // 先解锁再触发条件可提高效率
922    ///             cvar.broadcast();
923    ///         });
924    ///     let (lock, cvar) = &*pair;
925    ///     {
926    ///         let mut guard = lock.lock(SeqlockMode::ReadExclusiveLockCpuirqSave(None));
927    ///         while *guard {
928    ///             match guard.wait_unintr(cvar) {
929    ///                 Ok(g) => { // 唤醒
930    ///                     guard = g;
931    ///                 },
932    ///                 Err(e) => { // 等待条件量失败
933    ///                     break;
934    ///                 },
935    ///             }
936    ///         }
937    ///     }
938    /// }
939    /// ```
940    ///
941    /// [`Err`]: <https://doc.rust-lang.org/core/result/enum.Result.html#variant.Err>
942    pub fn wait_unintr(self, cond: &Cond) -> Result<SeqlockGuard<'a, T>, CondError> {
943        unsafe {
944            let mut rc = xwrustffi_cond_acquire(cond.cond.get(), *cond.tik.get());
945            if rc == 0 {
946                let lktype = match &*self.lock.mode.get() {
947                    SeqlockMode::WriteLock |
948                    SeqlockMode::WriteLockBh |
949                    SeqlockMode::WriteLockCpuirq |
950                    SeqlockMode::WriteLockCpuirqSave(_) => {
951                        XWOS_LK_SQLK_WR
952                    },
953                    SeqlockMode::ReadExclusiveLock |
954                    SeqlockMode::ReadExclusiveLockBh |
955                    SeqlockMode::ReadExclusiveLockCpuirq |
956                    SeqlockMode::ReadExclusiveLockCpuirqSave(_) => {
957                        XWOS_LK_SQLK_RDEX
958                    },
959                };
960                let mut lkst = 0;
961                rc = xwrustffi_cond_wait_unintr(cond.cond.get(),
962                                                self.lock.sqlk.get() as _, lktype, ptr::null_mut(),
963                                                &mut lkst);
964                xwrustffi_cond_put(cond.cond.get());
965                if 0 == rc {
966                    Ok(self)
967                } else {
968                    if XWOS_LKST_LOCKED == lkst {
969                        drop(self);
970                    } else {
971                        self.lock();
972                        drop(self);
973                    }
974                    if -EINTR == rc {
975                        Err(CondError::Interrupt(rc))
976                    } else if -ENOTTHDCTX == rc {
977                        Err(CondError::NotThreadContext(rc))
978                    } else {
979                        Err(CondError::Unknown(rc))
980                    }
981                }
982            } else {
983                drop(self);
984                Err(CondError::NotInit(rc))
985            }
986        }
987    }
988}
989
990impl<T: ?Sized> Deref for SeqlockGuard<'_, T> {
991    type Target = T;
992
993    fn deref(&self) -> &T {
994        unsafe { &*self.lock.data.get() }
995    }
996}
997
998impl<T: ?Sized> DerefMut for SeqlockGuard<'_, T> {
999    fn deref_mut(&mut self) -> &mut T {
1000        unsafe { &mut *self.lock.data.get() }
1001    }
1002}
1003
1004impl<T: ?Sized> Drop for SeqlockGuard<'_, T> {
1005    fn drop(&mut self) {
1006        unsafe {
1007            match *self.lock.mode.get() {
1008                SeqlockMode::ReadExclusiveLock => {
1009                    xwrustffi_sqlk_rdex_unlock(self.lock.sqlk.get());
1010                },
1011                SeqlockMode::ReadExclusiveLockCpuirq => {
1012                    xwrustffi_sqlk_rdex_unlock_cpuirq(self.lock.sqlk.get());
1013                },
1014                SeqlockMode::ReadExclusiveLockCpuirqSave(cpuirq) => {
1015                    xwrustffi_sqlk_rdex_unlock_cpuirqrs(self.lock.sqlk.get(), cpuirq.unwrap_unchecked());
1016                },
1017                SeqlockMode::ReadExclusiveLockBh => {
1018                    xwrustffi_sqlk_rdex_unlock_bh(self.lock.sqlk.get());
1019                },
1020
1021                SeqlockMode::WriteLock => {
1022                    xwrustffi_sqlk_wr_unlock(self.lock.sqlk.get());
1023                },
1024                SeqlockMode::WriteLockCpuirq => {
1025                    xwrustffi_sqlk_wr_unlock_cpuirq(self.lock.sqlk.get());
1026                },
1027                SeqlockMode::WriteLockCpuirqSave(cpuirq) => {
1028                    xwrustffi_sqlk_wr_unlock_cpuirqrs(self.lock.sqlk.get(), cpuirq.unwrap_unchecked());
1029                },
1030                SeqlockMode::WriteLockBh => {
1031                    xwrustffi_sqlk_wr_unlock_bh(self.lock.sqlk.get());
1032                },
1033            }
1034        }
1035    }
1036}