os/sync/
mutex.rs

1use super::UPSafeCell;
2use crate::task::TaskControlBlock;
3use crate::task::{block_current_and_run_next, suspend_current_and_run_next};
4use crate::task::{current_task, wakeup_task};
5use alloc::{collections::VecDeque, sync::Arc};
6
7pub trait Mutex: Sync + Send {
8    fn lock(&self);
9    fn unlock(&self);
10}
11
12pub struct MutexSpin {
13    locked: UPSafeCell<bool>,
14}
15
16impl MutexSpin {
17    pub fn new() -> Self {
18        Self {
19            locked: unsafe { UPSafeCell::new(false) },
20        }
21    }
22}
23
24impl Mutex for MutexSpin {
25    fn lock(&self) {
26        loop {
27            let mut locked = self.locked.exclusive_access();
28            if *locked {
29                drop(locked);
30                suspend_current_and_run_next();
31                continue;
32            } else {
33                *locked = true;
34                return;
35            }
36        }
37    }
38
39    fn unlock(&self) {
40        let mut locked = self.locked.exclusive_access();
41        *locked = false;
42    }
43}
44
45pub struct MutexBlocking {
46    inner: UPSafeCell<MutexBlockingInner>,
47}
48
49pub struct MutexBlockingInner {
50    locked: bool,
51    wait_queue: VecDeque<Arc<TaskControlBlock>>,
52}
53
54impl MutexBlocking {
55    pub fn new() -> Self {
56        Self {
57            inner: unsafe {
58                UPSafeCell::new(MutexBlockingInner {
59                    locked: false,
60                    wait_queue: VecDeque::new(),
61                })
62            },
63        }
64    }
65}
66
67impl Mutex for MutexBlocking {
68    fn lock(&self) {
69        let mut mutex_inner = self.inner.exclusive_access();
70        if mutex_inner.locked {
71            mutex_inner.wait_queue.push_back(current_task().unwrap());
72            drop(mutex_inner);
73            block_current_and_run_next();
74        } else {
75            mutex_inner.locked = true;
76        }
77    }
78
79    fn unlock(&self) {
80        let mut mutex_inner = self.inner.exclusive_access();
81        assert!(mutex_inner.locked);
82        if let Some(waking_task) = mutex_inner.wait_queue.pop_front() {
83            wakeup_task(waking_task);
84        } else {
85            mutex_inner.locked = false;
86        }
87    }
88}