xref: /DragonOS/docs/kernel/sched/rust_waiting.md (revision 151251b50b7ed55596edd32ffec49a4041010e2a)
1*151251b5Slogin# 与“等待”相关的api(rust语言)
2*151251b5Slogin
3*151251b5Slogin  如果几个进程需要等待某个事件发生,才能被运行,那么就需要一种“等待”的机制,以实现进程同步。
4*151251b5Slogin
5*151251b5Slogin## 1. WaitQueue等待队列
6*151251b5Slogin
7*151251b5Slogin   WaitQueue是一种进程同步机制,中文名为“等待队列”。它可以将当前进程挂起,并在时机成熟时,由另一个进程唤醒他们。
8*151251b5Slogin
9*151251b5Slogin  当您需要等待一个事件完成时,使用 WaitQueue机制能减少进程同步的开销。相比于滥用自旋锁以及信号量,或者是循环使用usleep(1000)这样的函数来完成同步, WaitQueue是一个高效的解决方案。
10*151251b5Slogin
11*151251b5Slogin### 1.1 WaitQueue的使用
12*151251b5Slogin
13*151251b5Slogin   WaitQueue的使用非常简单,只需要三步:
14*151251b5Slogin
15*151251b5Slogin1. 初始化一个WaitQueue对象。
16*151251b5Slogin2. 调用这个WaitQueue的挂起相关的API,将当前进程挂起。
17*151251b5Slogin3. 当事件发生时,由另一个进程,调用这个WaitQueue的唤醒相关的API,唤醒一个进程。
18*151251b5Slogin
19*151251b5Slogin  下面是一个简单的例子:
20*151251b5Slogin
21*151251b5Slogin### 1.1.1 初始化一个WaitQueue对象
22*151251b5Slogin
23*151251b5Slogin   WaitQueue对象的初始化非常简单,只需要调用WaitQueue::INIT即可。
24*151251b5Slogin
25*151251b5Slogin```rust
26*151251b5Sloginlet mut wq = WaitQueue::INIT;
27*151251b5Slogin```
28*151251b5Slogin
29*151251b5Slogin### 1.1.2 挂起进程
30*151251b5Slogin
31*151251b5Slogin   您可以这样挂起当前进程:
32*151251b5Slogin
33*151251b5Slogin```rust
34*151251b5Sloginwq.sleep();
35*151251b5Slogin```
36*151251b5Slogin
37*151251b5Slogin   当前进程会被挂起,直到有另一个进程调用了`wq.wakeup()`。
38*151251b5Slogin
39*151251b5Slogin### 1.1.3 唤醒进程
40*151251b5Slogin
41*151251b5Slogin   您可以这样唤醒一个进程:
42*151251b5Slogin
43*151251b5Slogin```rust
44*151251b5Slogin// 唤醒等待队列头部的进程(如果它的state & PROC_INTERRUPTIBLE 不为0)
45*151251b5Sloginwq.wakeup(PROC_INTERRUPTIBLE);
46*151251b5Slogin
47*151251b5Slogin// 唤醒等待队列头部的进程(如果它的state & PROC_UNINTERRUPTIBLE 不为0)
48*151251b5Sloginwq.wakeup(PROC_UNINTERRUPTIBLE);
49*151251b5Slogin
50*151251b5Slogin// 唤醒等待队列头部的进程(无论它的state是什么)
51*151251b5Sloginwq.wakeup((-1) as u64);
52*151251b5Slogin```
53*151251b5Slogin
54*151251b5Slogin### 1.2 API
55*151251b5Slogin
56*151251b5Slogin### 1.2.1 挂起进程
57*151251b5Slogin
58*151251b5Slogin  您可以使用以下函数,将当前进程挂起,并插入到指定的等待队列。这些函数大体功能相同,只是在一些细节上有所不同。
59*151251b5Slogin
60*151251b5Slogin| 函数名                                     | 解释                                                            |
61*151251b5Slogin| --------------------------------------- | ------------------------------------------------------------- |
62*151251b5Slogin| sleep()                                 | 将当前进程挂起,并设置进程状态为PROC_INTERRUPTIBLE                            |
63*151251b5Slogin| sleep_uninterruptible()                 | 将当前进程挂起,并设置进程状态为PROC_UNINTERRUPTIBLE                          |
64*151251b5Slogin| sleep_unlock_spinlock()                 | 将当前进程挂起,并设置进程状态为PROC_INTERRUPTIBLE。待当前进程被插入等待队列后,解锁给定的自旋锁     |
65*151251b5Slogin| sleep_unlock_mutex()                    | 将当前进程挂起,并设置进程状态为PROC_INTERRUPTIBLE。待当前进程被插入等待队列后,解锁给定的Mutex   |
66*151251b5Slogin| sleep_uninterruptible_unlock_spinlock() | 将当前进程挂起,并设置进程状态为PROC_UNINTERRUPTIBLE。待当前进程被插入等待队列后,解锁给定的自旋锁   |
67*151251b5Slogin| sleep_uninterruptible_unlock_mutex()    | 将当前进程挂起,并设置进程状态为PROC_UNINTERRUPTIBLE。待当前进程被插入等待队列后,解锁给定的Mutex |
68*151251b5Slogin
69*151251b5Slogin### 1.2.2 唤醒进程
70*151251b5Slogin
71*151251b5Slogin  您可以使用`wakeup(state)`函数,唤醒等待队列中的第一个进程。如果这个进程的state与给定的state进行and操作之后,结果不为0,则唤醒它。
72*151251b5Slogin
73*151251b5Slogin  返回值:如果有进程被唤醒,则返回true,否则返回false。
74*151251b5Slogin
75*151251b5Slogin### 1.2.3 其它API
76*151251b5Slogin
77*151251b5Slogin| 函数名   | 解释           |
78*151251b5Slogin| ----- | ------------ |
79*151251b5Slogin| len() | 返回等待队列中的进程数量 |
80*151251b5Slogin
81*151251b5Slogin
82