xwrust/xwos/lock/spinlock.rs
1//! XWOS RUST:自旋锁
2//! ========
3//!
4//! 自旋锁是多核系统中为防止多个处理器同时访问临界区而引入的一种锁。
5//! 当一个CPU获得自旋锁并访问临界区时,其他CPU只能 **自旋** 等待。
6//! 所谓 **自旋** ,是指不断循环测试锁的是否可用。
7//!
8//! 自旋锁内的操作是不可被打断的。因此,自旋锁还伴随其他操作,
9//! 例如关闭调度器的抢占,关闭中断底半部,关闭中断等。
10//!
11//! 在单核(UP)系统中,只有一个CPU,不需要自旋过程,单核系统为了软件接口与多核系统兼容,
12//! 也会实现自旋锁,这种自旋锁只需关闭抢占、中断底半部或中断。
13//!
14//! 自旋锁可用在 **任何上下文(Context)** :
15//!
16//! + 当临界区只被多个线程访问时,需使用关闭抢占的模式: [`SpinlockMode::Lock`]
17//! + 当临界区被中断底半部访问时,需使用关闭中断底半部的模式: [`SpinlockMode::LockBh`]
18//! + 当临界区被多个线程和单一中断访问时,需使用关闭全局中断的模式: [`SpinlockMode::LockCpuirq`]
19//! + 当临界区被多个中断上下文访问时,需使用保存中断全局标志并关闭全局中断的模式: [`SpinlockMode::LockCpuirqSave(None)`]
20//!
21//!
22//! # 创建
23//!
24//! XWOS RUST的自旋锁可使用 [`Spinlock::new()`] 创建:
25//!
26//! + 可以创建具有静态生命周期 [`static`] 约束的全局变量:
27//!
28//! ```rust
29//! use xwrust::xwos::lock::spinlock::*;
30//!
31//! static GLOBAL_SPINLOCK: Spinlock<u32> = Spinlock::new(0);
32//! ```
33//!
34//! + 也可以使用 [`alloc::sync::Arc`] 在heap中创建:
35//!
36//! ```rust
37//! extern crate alloc;
38//! use alloc::sync::Arc;
39//!
40//! use xwrust::xwos::lock::spinlock::*;
41//!
42//! pub fn xwrust_example_spinlock() {
43//! let spinlock: Arc<Spinlock<u32>> = Arc::new(Spinlock::new(0));
44//! }
45//! ```
46//!
47//!
48//! # 解锁
49//!
50//! 上锁后返回的 [`SpinlockGuard`] 。 [`SpinlockGuard`] 的生命周期结束时,会自动解锁。
51//! 也可调用 [`Spinlock::unlock()`] 主动消费掉 [`SpinlockGuard`] 来解锁。
52//!
53//!
54//! # 上锁
55//!
56//! 上锁的方法 [`Spinlock::lock()`] 除了 **自旋** 等待,还会根据上锁模式增加额外操作:
57//!
58//! + 只关闭抢占的模式: [`SpinlockMode::Lock`]
59//! + 关闭中断底半部的模式: [`SpinlockMode::LockBh`]
60//! + 关闭全局中断的模式: [`SpinlockMode::LockCpuirq`]
61//! + 保存中断全局标志并关闭全局中断的模式: [`SpinlockMode::LockCpuirqSave(None)`]
62//!
63//!
64//! # 尝试上锁
65//!
66//! 尝试上锁的方法 [`Spinlock::trylock()`] 只会测试一下锁,不会 **自旋** 等待,上锁成功后还会根据上锁模式增加额外操作:
67//!
68//! + 只关闭抢占的模式: [`SpinlockMode::Lock`]
69//! + 关闭中断底半部的模式: [`SpinlockMode::LockBh`]
70//! + 关闭全局中断的模式: [`SpinlockMode::LockCpuirq`]
71//! + 保存中断全局标志并关闭全局中断的模式: [`SpinlockMode::LockCpuirqSave(None)`]
72//!
73//!
74//! # 示例
75//!
76//! [XWOS/xwam/xwrust-example/xwrust_example_spinlock](https://gitee.com/xwos/XWOS/blob/main/xwam/xwrust-example/xwrust_example_spinlock/src/lib.rs)
77//!
78//!
79//! [`SpinlockMode::LockCpuirqSave(None)`]: SpinlockMode::LockCpuirqSave
80//! [`static`]: https://doc.rust-lang.org/std/keyword.static.html
81//! [`alloc::sync::Arc`]: <https://doc.rust-lang.org/alloc/sync/struct.Arc.html>
82
83extern crate core;
84use core::cell::UnsafeCell;
85use core::result::Result;
86use core::default::Default;
87use core::option::Option;
88use core::ops::Drop;
89use core::ops::Deref;
90use core::ops::DerefMut;
91use core::ptr;
92
93use crate::types::*;
94use crate::errno::*;
95
96use crate::xwos::sync::cond::*;
97
98extern "C" {
99 fn xwrustffi_splk_init(splk: *mut XwosSplk);
100 fn xwrustffi_splk_unlock(splk: *mut XwosSplk);
101 fn xwrustffi_splk_lock(splk: *mut XwosSplk);
102 fn xwrustffi_splk_trylock(splk: *mut XwosSplk) -> XwEr;
103 fn xwrustffi_splk_unlock_cpuirq(splk: *mut XwosSplk);
104 fn xwrustffi_splk_lock_cpuirq(splk: *mut XwosSplk);
105 fn xwrustffi_splk_trylock_cpuirq(splk: *mut XwosSplk) -> XwEr;
106 fn xwrustffi_splk_unlock_cpuirqrs(splk: *mut XwosSplk, cpuirq: XwReg);
107 fn xwrustffi_splk_lock_cpuirqsv(splk: *mut XwosSplk, cpuirq: *mut XwReg);
108 fn xwrustffi_splk_trylock_cpuirqsv(splk: *mut XwosSplk, cpuirq: *mut XwReg) -> XwEr;
109 fn xwrustffi_splk_unlock_bh(splk: *mut XwosSplk);
110 fn xwrustffi_splk_lock_bh(splk: *mut XwosSplk);
111 fn xwrustffi_splk_trylock_bh(splk: *mut XwosSplk) -> XwEr;
112}
113
114/// 自旋锁的错误码
115#[derive(Debug)]
116pub enum SpinlockError {
117 /// 尝试上锁失败
118 Again(XwEr),
119 /// 未知错误
120 Unknown(XwEr),
121}
122
123impl SpinlockError {
124 /// 消费掉 `SpinlockError` 自身,返回内部的错误码。
125 pub fn unwrap(self) -> XwEr {
126 match self {
127 Self::Again(rc) => rc,
128 Self::Unknown(rc) => rc,
129 }
130 }
131}
132
133/// 自旋锁的上锁模式
134pub enum SpinlockMode {
135 /// 关闭抢占
136 Lock,
137 /// 关闭抢占、中断底半部
138 LockBh,
139 /// 关闭抢占、中断底半部和中断
140 LockCpuirq,
141 /// 关闭抢占、中断底半部和中断,并保存之前的中断标志
142 LockCpuirqSave(Option<XwReg>),
143}
144
145/// XWOS自旋锁占用的内存大小
146#[cfg(target_pointer_width = "32")]
147pub const SIZEOF_XWOS_SPLK: usize = 8;
148
149/// XWOS自旋锁占用的内存大小
150#[cfg(target_pointer_width = "64")]
151pub const SIZEOF_XWOS_SPLK: usize = 8;
152
153/// 用于构建自旋锁的内存数组类型
154#[repr(C)]
155#[cfg_attr(target_pointer_width = "32", repr(align(8)))]
156#[cfg_attr(target_pointer_width = "64", repr(align(16)))]
157pub(crate) struct XwosSplk {
158 pub(crate) obj: [u8; SIZEOF_XWOS_SPLK],
159}
160
161/// 用于构建自旋锁的内存数组常量
162pub(crate) const XWOS_SPLK_INITIALIZER: XwosSplk = XwosSplk {
163 obj: [0; SIZEOF_XWOS_SPLK],
164};
165
166
167/// 自旋锁结构体
168pub struct Spinlock<T: ?Sized> {
169 /// XWOS自旋锁
170 pub(crate) splk: UnsafeCell<XwosSplk>,
171 /// 上锁方式
172 pub(crate) mode: UnsafeCell<SpinlockMode>,
173 /// 用户数据
174 pub data: UnsafeCell<T>,
175}
176
177impl<T> Spinlock<T> {
178 /// 新建自旋锁
179 ///
180 /// 此方法是编译期方法,可用于新建 [`static`] 约束的全局变量。
181 ///
182 /// # 示例
183 ///
184 /// ```rust
185 /// use xwrust::xwos::lock::spinlock::*;
186 ///
187 /// static GLOBAL_SPINLOCK: Spinlock<u32> = Spinlock::new(0);
188 /// ```
189 ///
190 /// [`static`]: https://doc.rust-lang.org/std/keyword.static.html
191 pub const fn new(t: T) -> Self {
192 Self {
193 splk: UnsafeCell::new(XWOS_SPLK_INITIALIZER),
194 mode: UnsafeCell::new(SpinlockMode::Lock),
195 data: UnsafeCell::new(t),
196 }
197 }
198}
199
200impl<T: ?Sized> Spinlock<T> {
201 /// 获取自旋锁,若线程无法获取自旋锁,就阻塞等待,直到能获得锁为止
202 ///
203 /// + 若成功获取自旋锁,将返回 **RAII Guard** : [`SpinlockGuard`] ,用于提供 **Scoped Lock** 机制。
204 /// + [`SpinlockGuard`] 中包含 [`Spinlock`] 的引用, 当 [`SpinlockGuard`] 生命周期结束时,会在 [`drop()`] 方法中自动解锁自旋锁。
205 /// + 若失败,将返回错误码 [`SpinlockError`] 。
206 ///
207 /// # 参数说明
208 ///
209 /// + mode: 锁模式
210 /// + [`SpinlockMode::Lock`] 关闭抢占
211 /// + [`SpinlockMode::LockBh`] 关闭抢占、中断底半部
212 /// + [`SpinlockMode::LockCpuirq`] 关闭抢占、中断底半部和中断
213 /// + [`SpinlockMode::LockCpuirqSave(None)`] 关闭抢占、中断底半部和中断,并保存之前的中断标志
214 ///
215 /// # 示例
216 ///
217 /// ```rust
218 /// use xwrust::xwos::lock::spinlock::*;
219 /// static GLOBAL_SPINLOCK: Spinlock<u32> = Spinlock::new(0);
220 ///
221 /// pub fn xwrust_example_spinlock() {
222 /// // ...省略...
223 /// let mut guard = GLOBAL_SPINLOCK.lock();
224 /// *guard = 1; // 访问共享变量
225 /// drop(guard); // 解锁
226 /// }
227 /// ```
228 ///
229 /// [`SpinlockMode::LockCpuirqSave(None)`]: SpinlockMode::LockCpuirqSave
230 /// [`drop()`]: https://doc.rust-lang.org/std/mem/fn.drop.html
231 pub fn lock(&self, mode: SpinlockMode) -> SpinlockGuard<'_, T> {
232 unsafe {
233 match mode {
234 SpinlockMode::Lock => {
235 xwrustffi_splk_lock(self.splk.get());
236 *self.mode.get() = SpinlockMode::Lock;
237 },
238 SpinlockMode::LockCpuirq => {
239 xwrustffi_splk_lock_cpuirq(self.splk.get());
240 *self.mode.get() = SpinlockMode::LockCpuirq;
241 },
242 SpinlockMode::LockCpuirqSave(_) => {
243 let mut cpuirq: XwReg = 0;
244 xwrustffi_splk_lock_cpuirqsv(self.splk.get(), &mut cpuirq);
245 *self.mode.get() = SpinlockMode::LockCpuirqSave(Some(cpuirq));
246 },
247 SpinlockMode::LockBh => {
248 xwrustffi_splk_lock_bh(self.splk.get());
249 *self.mode.get() = SpinlockMode::LockBh;
250 },
251 }
252 SpinlockGuard::new(self)
253 }
254 }
255
256 /// 尝试获取自旋锁,若线程无法获取自旋锁,立即返回错误
257 ///
258 /// + 若成功获取自旋锁,将返回 **RAII Guard** : [`SpinlockGuard`] ,用于提供 **Scoped Lock** 机制。
259 /// + [`SpinlockGuard`] 中包含 [`Spinlock`] 的引用, 当 [`SpinlockGuard`] 生命周期结束时,会在 [`drop()`] 方法中自动解锁自旋锁。
260 /// + 若失败,将返回错误码 [`SpinlockError`] 。
261 ///
262 /// # 参数说明
263 ///
264 /// + mode: 锁模式
265 /// + [`SpinlockMode::Lock`] 关闭抢占
266 /// + [`SpinlockMode::LockBh`] 关闭抢占、中断底半部
267 /// + [`SpinlockMode::LockCpuirq`] 关闭抢占、中断底半部和中断
268 /// + [`SpinlockMode::LockCpuirqSave(None)`] 关闭抢占、中断底半部和中断,并保存之前的中断标志
269 ///
270 /// # 错误码
271 ///
272 /// + [`SpinlockError::Again`] 尝试获取锁失败
273 ///
274 /// # 示例
275 /// ```rust
276 /// use xwrust::xwos::lock::spinlock::*;
277 /// static GLOBAL_SPINLOCK: Spinlock<u32> = Spinlock::new(0);
278 ///
279 /// pub fn xwrust_example_spinlock() {
280 /// // ...省略...
281 /// match GLOBAL_SPINLOCK.trylock() {
282 /// Ok(mut guard) => { // 上锁成功
283 /// *guard = 1; // 访问共享变量
284 /// } // guard 生命周期结束,自动解锁
285 /// Err(e) => {
286 /// // 上锁失败
287 /// }
288 /// }
289 /// }
290 /// ```
291 ///
292 /// [`SpinlockMode::LockCpuirqSave(None)`]: SpinlockMode::LockCpuirqSave
293 /// [`drop()`]: https://doc.rust-lang.org/std/mem/fn.drop.html
294 pub fn trylock(&self, mode: SpinlockMode) -> Result<SpinlockGuard<'_, T>, SpinlockError> {
295 unsafe {
296 let rc: XwEr;
297 match mode {
298 SpinlockMode::Lock => {
299 rc = xwrustffi_splk_trylock(self.splk.get());
300 if 0 == rc {
301 *self.mode.get() = SpinlockMode::Lock;
302 Ok(SpinlockGuard::new(self))
303 } else if -EAGAIN == rc {
304 Err(SpinlockError::Again(rc))
305 } else {
306 Err(SpinlockError::Unknown(rc))
307 }
308 },
309 SpinlockMode::LockCpuirq => {
310 rc = xwrustffi_splk_trylock_cpuirq(self.splk.get());
311 if 0 == rc {
312 *self.mode.get() = SpinlockMode::LockCpuirq;
313 Ok(SpinlockGuard::new(self))
314 } else if -EAGAIN == rc {
315 Err(SpinlockError::Again(rc))
316 } else {
317 Err(SpinlockError::Unknown(rc))
318 }
319 },
320 SpinlockMode::LockCpuirqSave(_) => {
321 let mut cpuirq: XwReg = 0;
322 rc = xwrustffi_splk_trylock_cpuirqsv(self.splk.get(), &mut cpuirq);
323 if 0 == rc {
324 *self.mode.get() = SpinlockMode::LockCpuirqSave(Some(cpuirq));
325 Ok(SpinlockGuard::new(self))
326 } else if -EAGAIN == rc {
327 Err(SpinlockError::Again(rc))
328 } else {
329 Err(SpinlockError::Unknown(rc))
330 }
331 },
332 SpinlockMode::LockBh => {
333 rc = xwrustffi_splk_trylock_bh(self.splk.get());
334 if 0 == rc {
335 *self.mode.get() = SpinlockMode::LockBh;
336 Ok(SpinlockGuard::new(self))
337 } else if -EAGAIN == rc {
338 Err(SpinlockError::Again(rc))
339 } else {
340 Err(SpinlockError::Unknown(rc))
341 }
342 },
343 }
344 }
345 }
346
347 /// 解锁自旋锁,并释放 [`SpinlockGuard`]
348 ///
349 /// # 示例
350 ///
351 /// ```rust
352 /// use xwrust::xwos::lock::spinlock::*;
353 /// static GLOBAL_SPINLOCK: Spinlock<u32> = Spinlock::new(0);
354 ///
355 /// pub fn xwrust_example_spinlock() {
356 /// // ...省略...
357 /// let mut guard = GLOBAL_SPINLOCK.lock();
358 /// *guard = 1; // 访问共享变量
359 /// Spinlock::unlock(guard); // 主动解锁
360 /// }
361 /// ```
362 ///
363 /// [`drop()`]: https://doc.rust-lang.org/std/mem/fn.drop.html
364 pub fn unlock(guard: SpinlockGuard<'_, T>) {
365 drop(guard)
366 }
367}
368
369unsafe impl<T: ?Sized + Send> Send for Spinlock<T> {}
370unsafe impl<T: ?Sized + Send> Sync for Spinlock<T> {}
371
372impl<T> From<T> for Spinlock<T> {
373 /// 从数据新建自旋锁
374 ///
375 /// 此方法会将数据所有权转移到自旋锁的内部
376 ///
377 /// 等价于 [`Spinlock::new`]
378 fn from(t: T) -> Self {
379 Spinlock::new(t)
380 }
381}
382
383impl<T: ?Sized + Default> Default for Spinlock<T> {
384 fn default() -> Spinlock<T> {
385 Spinlock::new(Default::default())
386 }
387}
388
389impl<T: ?Sized> Drop for Spinlock<T> {
390 fn drop(&mut self) {
391 }
392}
393
394/// 自旋锁的RAII Guard
395///
396/// **RAII Guard** 用于提供 **Scoped Lock** 机制。
397///
398/// + [`SpinlockGuard`] 中包含 [`Spinlock`] 的引用, 当 [`SpinlockGuard`] 生命周期结束时,会在 [`drop()`] 方法中自动解锁自旋锁。
399/// + [`SpinlockGuard`] 不可在线程之间转移所有权,因为其 [`drop()`] 方法包含解锁的语义,上锁和解锁必须在同一线程;
400/// + [`SpinlockGuard`] 虽然可以在多线程中传递引用( [`Sync`] 约束),但其实现中没有 **unlock()** 方法,意味着其他线程即便拿到引用也不能解锁。
401///
402/// [`drop()`]: https://doc.rust-lang.org/std/mem/fn.drop.html
403/// [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Send.html
404pub struct SpinlockGuard<'a, T: ?Sized + 'a> {
405 /// 自旋锁的引用
406 lock: &'a Spinlock<T>,
407}
408
409impl<T: ?Sized> !Send for SpinlockGuard<'_, T> {}
410unsafe impl<T: ?Sized + Sync> Sync for SpinlockGuard<'_, T> {}
411
412impl<'a, T: ?Sized> SpinlockGuard<'a, T> {
413 fn new(lock: &'a Spinlock<T>) -> SpinlockGuard<'a, T> {
414 SpinlockGuard { lock: lock }
415 }
416
417 fn lock(&self) {
418 unsafe {
419 xwrustffi_splk_lock(self.lock.splk.get());
420 }
421 }
422
423 fn unlock(&self) {
424 unsafe {
425 xwrustffi_splk_unlock(self.lock.splk.get());
426 }
427 }
428
429 /// 阻塞当前线程,直到被条件量唤醒
430 ///
431 /// 此方法会消费自旋锁的守卫(Guard),并当线程阻塞时,在条件量内部释放自旋锁。
432 /// 当条件成立,线程被唤醒,会在条件量内部上锁自旋锁,并重新返回自旋锁的守卫(Guard)。
433 ///
434 /// + 当返回自旋锁的守卫 [`SpinlockGuard`] 时,自旋锁已经被重新上锁;
435 /// + 当返回 [`Err`] 时,自旋锁未被上锁。
436 ///
437 /// # 参数说明
438 ///
439 /// + cond: 条件量的引用
440 ///
441 /// # 错误码
442 ///
443 /// + [`CondError::NotInit`] 条件量未被初始化
444 /// + [`CondError::Interrupt`] 等待被中断
445 /// + [`CondError::NotThreadContext`] 不在线程上下文中
446 ///
447 /// # 示例
448 ///
449 /// ```rust
450 /// use xwrust::xwos::thd;
451 /// use xwrust::xwos::lock::spinlock::*;
452 /// use xwrust::xwos::sync::cond::*;
453 /// extern crate alloc;
454 /// use alloc::sync::Arc;
455 ///
456 /// pub fn xwrust_example_spinlock() {
457 /// let pair = Arc::new((Spinlock::new(true), Cond::new()));
458 /// pair.1.init();
459 /// let pair_c = pair.clone();
460 ///
461 /// thd::Builder::new()
462 /// .name("child".into())
463 /// .spawn(move |_| { // 子线程闭包
464 /// cthd::sleep(xwtm::ms(500));
465 /// let (lock, cvar) = &*pair_c;
466 /// let mut guard = lock_child.lock();
467 /// *guard = false; // 设置共享数据
468 /// drop(guard); // 先解锁再触发条件可提高效率
469 /// cvar.broadcast();
470 /// });
471 /// let (lock, cvar) = &*pair;
472 /// {
473 /// let mut guard = lock.lock();
474 /// while *guard {
475 /// match guard.wait(cvar) {
476 /// Ok(g) => { // 唤醒
477 /// guard = g; // 重新捕获守卫
478 /// },
479 /// Err(e) => { // 等待条件量失败
480 /// break;
481 /// },
482 /// }
483 /// }
484 /// }
485 /// }
486 /// ```
487 ///
488 /// [`Err`]: <https://doc.rust-lang.org/core/result/enum.Result.html#variant.Err>
489 pub fn wait(self, cond: &Cond) -> Result<SpinlockGuard<'a, T>, CondError> {
490 unsafe {
491 let mut rc = xwrustffi_cond_acquire(cond.cond.get(), *cond.tik.get());
492 if rc == 0 {
493 let mut lkst = 0;
494 rc = xwrustffi_cond_wait(cond.cond.get(),
495 self.lock.splk.get() as _, XWOS_LK_SPLK, ptr::null_mut(),
496 &mut lkst);
497 xwrustffi_cond_put(cond.cond.get());
498 if 0 == rc {
499 Ok(self)
500 } else {
501 if XWOS_LKST_LOCKED == lkst {
502 drop(self);
503 } else {
504 self.lock();
505 drop(self);
506 }
507 if -EINTR == rc {
508 Err(CondError::Interrupt(rc))
509 } else if -ENOTTHDCTX == rc {
510 Err(CondError::NotThreadContext(rc))
511 } else {
512 Err(CondError::Unknown(rc))
513 }
514 }
515 } else {
516 drop(self);
517 Err(CondError::NotInit(rc))
518 }
519 }
520 }
521
522 /// 限时阻塞当前线程,直到被条件量唤醒
523 ///
524 /// 此方法会消费自旋锁的守卫(Guard),并当线程阻塞时,在条件量内部释放自旋锁。
525 /// 当条件成立,线程被唤醒,会在条件量内部上锁自旋锁,并重新返回自旋锁的守卫(Guard)。
526 /// 当超时后,将返回错误。
527 ///
528 /// + 当返回自旋锁的守卫 [`SpinlockGuard`] 时,自旋锁已经被重新上锁;
529 /// + 当返回 [`Err`] 时,自旋锁未被上锁。
530 ///
531 /// # 参数说明
532 ///
533 /// + cond: 条件量的引用
534 /// + to: 期望唤醒的时间点
535 ///
536 /// # 错误码
537 ///
538 /// + [`CondError::NotInit`] 条件量未被初始化
539 /// + [`CondError::Interrupt`] 等待被中断
540 /// + [`CondError::Timedout`] 等待超时
541 /// + [`CondError::NotThreadContext`] 不在线程上下文中
542 ///
543 /// # 示例
544 ///
545 /// ```rust
546 /// use xwrust::xwos::thd;
547 /// use xwrust::xwos::lock::spinlock::*;
548 /// use xwrust::xwos::sync::cond::*;
549 /// extern crate alloc;
550 /// use alloc::sync::Arc;
551 ///
552 /// pub fn xwrust_example_spinlock() {
553 /// let pair = Arc::new((Spinlock::new(true), Cond::new()));
554 /// pair.1.init();
555 /// let pair_c = pair.clone();
556 ///
557 /// thd::Builder::new()
558 /// .name("child".into())
559 /// .spawn(move |_| { // 子线程闭包
560 /// cthd::sleep(xwtm::ms(500));
561 /// let (lock, cvar) = &*pair_c;
562 /// let mut guard = lock_child.lock();
563 /// *guard = false; // 设置共享数据
564 /// drop(guard); // 先解锁再触发条件可提高效率
565 /// cvar.broadcast();
566 /// });
567 /// let (lock, cvar) = &*pair;
568 /// {
569 /// let mut guard = lock.lock();
570 /// while *guard {
571 /// match guard.wait_to(cvar, xwtm::ft(xwtm::s(2))) {
572 /// Ok(g) => { // 唤醒
573 /// guard = g; // 重新捕获守卫
574 /// },
575 /// Err(e) => { // 等待条件量失败
576 /// break;
577 /// },
578 /// }
579 /// }
580 /// }
581 /// }
582 /// ```
583 ///
584 /// [`Err`]: <https://doc.rust-lang.org/core/result/enum.Result.html#variant.Err>
585 pub fn wait_to(self, cond: &Cond, to: XwTm) -> Result<SpinlockGuard<'a, T>, CondError> {
586 unsafe {
587 let mut rc = xwrustffi_cond_acquire(cond.cond.get(), *cond.tik.get());
588 if rc == 0 {
589 let mut lkst = 0;
590 rc = xwrustffi_cond_wait_to(cond.cond.get(),
591 self.lock.splk.get() as _, XWOS_LK_SPLK, ptr::null_mut(),
592 to, &mut lkst);
593 xwrustffi_cond_put(cond.cond.get());
594 if 0 == rc {
595 Ok(self)
596 } else {
597 if XWOS_LKST_LOCKED == lkst {
598 drop(self);
599 } else {
600 self.lock();
601 drop(self);
602 }
603 if -EINTR == rc {
604 Err(CondError::Interrupt(rc))
605 } else if -ETIMEDOUT == rc {
606 Err(CondError::Timedout(rc))
607 } else if -ENOTTHDCTX == rc {
608 Err(CondError::NotThreadContext(rc))
609 } else {
610 Err(CondError::Unknown(rc))
611 }
612 }
613 } else {
614 drop(self);
615 Err(CondError::NotInit(rc))
616 }
617 }
618 }
619
620 /// 阻塞当前线程,直到被条件量唤醒,且阻塞不可被中断
621 ///
622 /// 此方法会消费自旋锁的守卫(Guard),并当线程阻塞时,在条件量内部释放自旋锁。
623 /// 当条件成立,线程被唤醒,会在条件量内部上锁自旋锁,并重新返回自旋锁的守卫(Guard)。
624 ///
625 /// + 当返回自旋锁的守卫 [`SpinlockGuard`] 时,自旋锁已经被重新上锁;
626 /// + 当返回 [`Err`] 时,自旋锁未被上锁。
627 ///
628 /// # 参数说明
629 ///
630 /// + cond: 条件量的引用
631 ///
632 /// # 错误码
633 ///
634 /// + [`CondError::NotInit`] 条件量未被初始化
635 /// + [`CondError::NotThreadContext`] 不在线程上下文中
636 ///
637 /// # 示例
638 ///
639 /// ```rust
640 /// use xwrust::xwos::thd;
641 /// use xwrust::xwos::lock::spinlock::*;
642 /// use xwrust::xwos::sync::cond::*;
643 /// extern crate alloc;
644 /// use alloc::sync::Arc;
645 ///
646 /// pub fn xwrust_example_spinlock() {
647 /// let pair = Arc::new((Spinlock::new(true), Cond::new()));
648 /// pair.1.init();
649 /// let pair_c = pair.clone();
650 ///
651 /// thd::Builder::new()
652 /// .name("child".into())
653 /// .spawn(move |_| { // 子线程闭包
654 /// cthd::sleep(xwtm::ms(500));
655 /// let (lock, cvar) = &*pair_c;
656 /// let mut guard = lock_child.lock();
657 /// *guard = false; // 设置共享数据
658 /// drop(guard); // 先解锁再触发条件可提高效率
659 /// cvar.broadcast();
660 /// });
661 /// let (lock, cvar) = &*pair;
662 /// {
663 /// let mut guard = lock.lock();
664 /// while *guard {
665 /// match guard.wait_unintr(cvar) {
666 /// Ok(g) => { // 唤醒
667 /// guard = g; // 重新捕获守卫
668 /// },
669 /// Err(e) => { // 等待条件量失败
670 /// break;
671 /// },
672 /// }
673 /// }
674 /// }
675 /// }
676 /// ```
677 ///
678 /// [`Err`]: <https://doc.rust-lang.org/core/result/enum.Result.html#variant.Err>
679 pub fn wait_unintr(self, cond: &Cond) -> Result<SpinlockGuard<'a, T>, CondError> {
680 unsafe {
681 let mut rc = xwrustffi_cond_acquire(cond.cond.get(), *cond.tik.get());
682 if rc == 0 {
683 let mut lkst = 0;
684 rc = xwrustffi_cond_wait_unintr(cond.cond.get(),
685 self.lock.splk.get() as _, XWOS_LK_SPLK, ptr::null_mut(),
686 &mut lkst);
687 xwrustffi_cond_put(cond.cond.get());
688 if 0 == rc {
689 Ok(self)
690 } else {
691 if XWOS_LKST_LOCKED == lkst {
692 drop(self);
693 } else {
694 self.lock();
695 drop(self);
696 }
697 if -EINTR == rc {
698 Err(CondError::Interrupt(rc))
699 } else if -ENOTTHDCTX == rc {
700 Err(CondError::NotThreadContext(rc))
701 } else {
702 Err(CondError::Unknown(rc))
703 }
704 }
705 } else {
706 drop(self);
707 Err(CondError::NotInit(rc))
708 }
709 }
710 }
711}
712
713impl<T: ?Sized> Deref for SpinlockGuard<'_, T> {
714 type Target = T;
715
716 fn deref(&self) -> &T {
717 unsafe { &*self.lock.data.get() }
718 }
719}
720
721impl<T: ?Sized> DerefMut for SpinlockGuard<'_, T> {
722 fn deref_mut(&mut self) -> &mut T {
723 unsafe { &mut *self.lock.data.get() }
724 }
725}
726
727impl<T: ?Sized> Drop for SpinlockGuard<'_, T> {
728 fn drop(&mut self) {
729 unsafe {
730 match *self.lock.mode.get() {
731 SpinlockMode::Lock => {
732 xwrustffi_splk_unlock(self.lock.splk.get());
733 },
734 SpinlockMode::LockCpuirq => {
735 xwrustffi_splk_unlock_cpuirq(self.lock.splk.get());
736 },
737 SpinlockMode::LockCpuirqSave(cpuirq) => {
738 xwrustffi_splk_unlock_cpuirqrs(self.lock.splk.get(), cpuirq.unwrap_unchecked());
739 },
740 SpinlockMode::LockBh => {
741 xwrustffi_splk_unlock_bh(self.lock.splk.get());
742 },
743 }
744 }
745 }
746}