Lab4: Lock

Armv8-A provides ldxr and stxr for exclusive access. You can either use compiler’s built-in function or hand written assembly. However, you need to enable MMU and data cache before using the ldxr instruction in real rpi3. So, you can now use a workaround such as disable preemption in real rpi3 or just give it a trial in QEMU which doesn’t have to enable MMU for ldxr.

Requirement

Implement mutex_lockmutex_unlock. If task fail to acquire the lock, it would go to sleep and context switch to other tasks.

Implementation

以 disable interrupt 方法為主,後續啟用 MMU 才會使用 exclusive access 的指令。

Demo

process 試著取得 lock 後馬上 scheule() 給下一個 process 去取得 lock,拿到 lock 後該 process 結束。一次只會有一個 process 拿到 lock,因此可見到 “Got lock” 交錯印出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <include/lock.h>
mutex_t shared_lock;

void task1()
{
while (1) {
printk("[PID %d] Kernel task 1...try to get lock\n", do_get_taskid());
int ret = mutex_trylock(&shared_lock);
enable_irq(); // Enable IRQ if it returns from IRQ handler
schedule();
if (ret == 0) {
printk("[PID %d] Got lock, exit...\n", do_get_taskid());
mutex_unlock(&shared_lock);
do_exit();
} else if (ret == EBUSY) {
printk("[PID %d] Already locked.\n", do_get_taskid());
}
}
}

void task2()
{
while (1) {
printk("[PID %d] Kernel task 2...try to get lock\n", do_get_taskid());
int ret = mutex_trylock(&shared_lock);
schedule();
enable_irq();
if (ret == 0) {
printk("[PID %d] Got lock, exit...\n", do_get_taskid());
mutex_unlock(&shared_lock);
do_exit();
} else if (ret == EBUSY) {
printk("[PID %d] Already locked.\n", do_get_taskid());
}
}
}

Reference

罗玉平: 关于ARM Linux原子操作的底层支持