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}