mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-09 07:06:47 +00:00
new: mutex
This commit is contained in:
parent
b98a3679c9
commit
946bbef392
@ -3,7 +3,7 @@ CFLAGS += -I .
|
|||||||
|
|
||||||
kernel_common_subdirs:=libELF math
|
kernel_common_subdirs:=libELF math
|
||||||
|
|
||||||
all: glib.o printk.o cpu.o bitree.o kfifo.o wait_queue.o
|
all: glib.o printk.o cpu.o bitree.o kfifo.o wait_queue.o mutex.o wait.o
|
||||||
@list='$(kernel_common_subdirs)'; for subdir in $$list; do \
|
@list='$(kernel_common_subdirs)'; for subdir in $$list; do \
|
||||||
echo "make all in $$subdir";\
|
echo "make all in $$subdir";\
|
||||||
cd $$subdir;\
|
cd $$subdir;\
|
||||||
@ -28,3 +28,9 @@ kfifo.o: kfifo.c
|
|||||||
|
|
||||||
wait_queue.o: wait_queue.c
|
wait_queue.o: wait_queue.c
|
||||||
gcc $(CFLAGS) -c wait_queue.c -o wait_queue.o
|
gcc $(CFLAGS) -c wait_queue.c -o wait_queue.o
|
||||||
|
|
||||||
|
mutex.o: mutex.c
|
||||||
|
gcc $(CFLAGS) -c mutex.c -o mutex.o
|
||||||
|
|
||||||
|
wait.o: sys/wait.c
|
||||||
|
gcc $(CFLAGS) -c sys/wait.c -o sys/wait.o
|
120
kernel/common/mutex.c
Normal file
120
kernel/common/mutex.c
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
#include <common/mutex.h>
|
||||||
|
#include <mm/slab.h>
|
||||||
|
#include <sched/sched.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化互斥量
|
||||||
|
*
|
||||||
|
* @param lock mutex结构体
|
||||||
|
*/
|
||||||
|
void mutex_init(mutex_t *lock)
|
||||||
|
{
|
||||||
|
atomic_set(&lock->count, 1);
|
||||||
|
spin_init(&lock->wait_lock);
|
||||||
|
list_init(&lock->wait_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __mutex_sleep()
|
||||||
|
{
|
||||||
|
current_pcb->state = PROC_UNINTERRUPTIBLE;
|
||||||
|
sched_cfs();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __mutex_acquire(mutex_t *lock)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief 对互斥量加锁
|
||||||
|
*
|
||||||
|
* @param lock mutex结构体
|
||||||
|
*/
|
||||||
|
void mutex_lock(mutex_t *lock)
|
||||||
|
{
|
||||||
|
bool lock_ok = 0;
|
||||||
|
|
||||||
|
while (lock_ok == false)
|
||||||
|
{
|
||||||
|
spin_lock(&lock->wait_lock);
|
||||||
|
if (likely(mutex_is_locked(lock)))
|
||||||
|
{
|
||||||
|
struct mutex_waiter_t *waiter = (struct mutex_waiter_t *)kmalloc(sizeof(struct mutex_waiter_t), 0);
|
||||||
|
if (waiter == NULL)
|
||||||
|
{
|
||||||
|
kerror("In mutex_lock: no memory to alloc waiter. Program's behaviour might be indetermined!");
|
||||||
|
spin_unlock(&lock->wait_lock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memset(waiter, 0, sizeof(struct mutex_waiter_t));
|
||||||
|
waiter->pcb = current_pcb;
|
||||||
|
list_init(&waiter->list);
|
||||||
|
list_append(&lock->wait_list, &waiter->list);
|
||||||
|
|
||||||
|
spin_unlock(&lock->wait_lock);
|
||||||
|
|
||||||
|
__mutex_sleep();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
atomic_dec(&lock->count);
|
||||||
|
spin_unlock(&lock->wait_lock);
|
||||||
|
lock_ok = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 对互斥量解锁
|
||||||
|
*
|
||||||
|
* @param lock mutex结构体
|
||||||
|
*/
|
||||||
|
void mutex_unlock(mutex_t *lock)
|
||||||
|
{
|
||||||
|
if (unlikely(!mutex_is_locked(lock)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
spin_lock(&lock->wait_lock);
|
||||||
|
struct mutex_waiter_t *wt = NULL;
|
||||||
|
if (mutex_is_locked(lock))
|
||||||
|
{
|
||||||
|
if (!list_empty(&lock->wait_list))
|
||||||
|
wt = container_of(list_next(&lock->wait_list), struct mutex_waiter_t, list);
|
||||||
|
|
||||||
|
atomic_inc(&lock->count);
|
||||||
|
if (wt != NULL)
|
||||||
|
list_del(&wt->list);
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_unlock(&lock->wait_lock);
|
||||||
|
|
||||||
|
if (wt != NULL)
|
||||||
|
{
|
||||||
|
process_wakeup(wt->pcb);
|
||||||
|
kfree(wt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 尝试对互斥量加锁
|
||||||
|
*
|
||||||
|
* @param lock mutex结构体
|
||||||
|
*
|
||||||
|
* @return 成功加锁->1, 加锁失败->0
|
||||||
|
*/
|
||||||
|
int mutex_trylock(mutex_t *lock)
|
||||||
|
{
|
||||||
|
if (mutex_is_locked(lock))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
spin_lock(&lock->wait_lock);
|
||||||
|
if (mutex_is_locked(lock))
|
||||||
|
{
|
||||||
|
spin_unlock(&lock->wait_lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
atomic_dec(&lock->count);
|
||||||
|
spin_unlock(&lock->wait_lock);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
69
kernel/common/mutex.h
Normal file
69
kernel/common/mutex.h
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <common/atomic.h>
|
||||||
|
#include <common/spinlock.h>
|
||||||
|
#include <common/glib.h>
|
||||||
|
#include <process/process.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Mutex - 互斥锁
|
||||||
|
*
|
||||||
|
* - 同一时间只有1个任务可以持有mutex
|
||||||
|
* - 不允许递归地加锁、解锁
|
||||||
|
* - 只允许通过mutex的api来操作mutex
|
||||||
|
* - 在硬中断、软中断中不能使用mutex
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
|
||||||
|
atomic_t count; // 锁计数。1->已解锁。 0->已上锁,且有可能存在等待者
|
||||||
|
spinlock_t wait_lock;
|
||||||
|
struct List wait_list;
|
||||||
|
} mutex_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 在mutex上的等待者的结构体
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct mutex_waiter_t
|
||||||
|
{
|
||||||
|
struct List list;
|
||||||
|
struct process_control_block *pcb;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化互斥量
|
||||||
|
*
|
||||||
|
* @param lock mutex结构体
|
||||||
|
*/
|
||||||
|
void mutex_init(mutex_t *lock);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 对互斥量加锁
|
||||||
|
*
|
||||||
|
* @param lock mutex结构体
|
||||||
|
*/
|
||||||
|
void mutex_lock(mutex_t *lock);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 对互斥量解锁
|
||||||
|
*
|
||||||
|
* @param lock mutex结构体
|
||||||
|
*/
|
||||||
|
void mutex_unlock(mutex_t *lock);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 尝试对互斥量加锁
|
||||||
|
*
|
||||||
|
* @param lock mutex结构体
|
||||||
|
*
|
||||||
|
* @return 成功加锁->1, 加锁失败->0
|
||||||
|
*/
|
||||||
|
int mutex_trylock(mutex_t *lock);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 判断mutex是否已被加锁
|
||||||
|
*
|
||||||
|
* @return 已加锁->1, 未加锁->0
|
||||||
|
*/
|
||||||
|
#define mutex_is_locked(lock) ((atomic_read(&(lock)->count) == 1) ? 0 : 1)
|
15
kernel/common/sys/wait.c
Normal file
15
kernel/common/sys/wait.c
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include <syscall/syscall_num.h>
|
||||||
|
#include <syscall/syscall.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 等待指定pid的子进程退出
|
||||||
|
*
|
||||||
|
* @param pid 子进程的pid
|
||||||
|
* @param stat_loc 返回的子进程结束状态
|
||||||
|
* @param options 额外的控制选项
|
||||||
|
* @return pid_t
|
||||||
|
*/
|
||||||
|
pid_t waitpid(pid_t pid, int *stat_loc, int options)
|
||||||
|
{
|
||||||
|
return (pid_t)enter_syscall_int(SYS_WAIT4, (uint64_t)pid, (uint64_t)stat_loc, options, 0, 0, 0, 0, 0);
|
||||||
|
}
|
12
kernel/common/sys/wait.h
Normal file
12
kernel/common/sys/wait.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 等待指定pid的子进程退出
|
||||||
|
*
|
||||||
|
* @param pid 子进程的pid
|
||||||
|
* @param stat_loc 返回的子进程结束状态
|
||||||
|
* @param options 额外的控制选项
|
||||||
|
* @return pid_t
|
||||||
|
*/
|
||||||
|
pid_t waitpid(pid_t pid, int *stat_loc, int options);
|
@ -2,7 +2,7 @@
|
|||||||
CFLAGS += -I .
|
CFLAGS += -I .
|
||||||
|
|
||||||
|
|
||||||
all: ktest.o bitree.o kfifo.o
|
all: ktest.o bitree.o kfifo.o mutex.o
|
||||||
|
|
||||||
ktest.o: ktest.c
|
ktest.o: ktest.c
|
||||||
gcc $(CFLAGS) -c ktest.c -o ktest.o
|
gcc $(CFLAGS) -c ktest.c -o ktest.o
|
||||||
@ -12,3 +12,6 @@ bitree.o: test-bitree.c
|
|||||||
|
|
||||||
kfifo.o: test-kfifo.c
|
kfifo.o: test-kfifo.c
|
||||||
gcc $(CFLAGS) -c test-kfifo.c -o test-kfifo.o
|
gcc $(CFLAGS) -c test-kfifo.c -o test-kfifo.o
|
||||||
|
|
||||||
|
mutex.o: test-mutex.c
|
||||||
|
gcc $(CFLAGS) -c test-mutex.c -o test-mutex.o
|
@ -3,10 +3,11 @@
|
|||||||
|
|
||||||
uint64_t ktest_test_bitree(uint64_t arg);
|
uint64_t ktest_test_bitree(uint64_t arg);
|
||||||
uint64_t ktest_test_kfifo(uint64_t arg);
|
uint64_t ktest_test_kfifo(uint64_t arg);
|
||||||
|
uint64_t ktest_test_mutex(uint64_t arg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 开启一个新的内核线程以进行测试
|
* @brief 开启一个新的内核线程以进行测试
|
||||||
*
|
*
|
||||||
* @param func 测试函数
|
* @param func 测试函数
|
||||||
* @param arg 传递给测试函数的参数
|
* @param arg 传递给测试函数的参数
|
||||||
* @return pid_t 测试内核线程的pid
|
* @return pid_t 测试内核线程的pid
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
printk("[ kTEST ] file:%s, Line:%d\t", __FILE__, __LINE__); \
|
printk("[ kTEST ] file:%s, Line:%d\t", __FILE__, __LINE__); \
|
||||||
printk(__VA_ARGS__); \
|
printk(__VA_ARGS__); \
|
||||||
printk("\n"); \
|
printk("\n"); \
|
||||||
} while (0);
|
} while (0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 测试用例函数表
|
* @brief 测试用例函数表
|
||||||
|
93
kernel/ktest/test-mutex.c
Normal file
93
kernel/ktest/test-mutex.c
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
#include "ktest_utils.h"
|
||||||
|
#include <common/mutex.h>
|
||||||
|
#include <common/time.h>
|
||||||
|
#include <common/sys/wait.h>
|
||||||
|
#include <process/process.h>
|
||||||
|
|
||||||
|
static mutex_t mtx;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 测试是否能够加锁
|
||||||
|
*
|
||||||
|
* @param arg0
|
||||||
|
* @param arg1
|
||||||
|
* @return long
|
||||||
|
*/
|
||||||
|
static long ktest_mutex_case0(uint64_t arg0, uint64_t arg1)
|
||||||
|
{
|
||||||
|
assert(mutex_is_locked(&mtx) == 0);
|
||||||
|
mutex_lock(&mtx);
|
||||||
|
assert(mutex_is_locked(&mtx) == 1);
|
||||||
|
mutex_unlock(&mtx);
|
||||||
|
assert(mutex_is_locked(&mtx) == 0);
|
||||||
|
assert(mutex_trylock(&mtx) == 1);
|
||||||
|
mutex_unlock(&mtx);
|
||||||
|
assert(mutex_is_locked(&mtx) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 测试用例1的辅助线程
|
||||||
|
*
|
||||||
|
* @param arg
|
||||||
|
* @return long
|
||||||
|
*/
|
||||||
|
static unsigned long ktest_mutex_case1_pid1(uint64_t arg)
|
||||||
|
{
|
||||||
|
kTEST("ktest_mutex_case1_subproc start.");
|
||||||
|
assert(mutex_is_locked(&mtx) == 1);
|
||||||
|
mutex_lock(&mtx);
|
||||||
|
assert(atomic_read(&mtx.count) == 0);
|
||||||
|
assert(list_empty(&mtx.wait_list));
|
||||||
|
|
||||||
|
mutex_unlock(&mtx);
|
||||||
|
kTEST("ktest_mutex_case1_subproc exit.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long ktest_mutex_case1(uint64_t arg0, uint64_t arg1)
|
||||||
|
{
|
||||||
|
if (!assert(mutex_is_locked(&mtx) == 0))
|
||||||
|
goto failed;
|
||||||
|
|
||||||
|
// 加锁
|
||||||
|
mutex_lock(&mtx);
|
||||||
|
// 启动另一个线程
|
||||||
|
pid_t pid = kernel_thread(ktest_mutex_case1_pid1, 0, 0);
|
||||||
|
// 等待100ms
|
||||||
|
usleep(100000);
|
||||||
|
while (list_empty(&mtx.wait_list))
|
||||||
|
;
|
||||||
|
|
||||||
|
// 当子线程加锁后,计数应当为0
|
||||||
|
assert(atomic_read(&mtx.count) == 0);
|
||||||
|
struct mutex_waiter_t *wt = container_of(list_next(&mtx.wait_list), struct mutex_waiter_t, list);
|
||||||
|
assert(wt->pcb->pid == pid);
|
||||||
|
|
||||||
|
mutex_unlock(&mtx);
|
||||||
|
|
||||||
|
int stat = 1;
|
||||||
|
waitpid(pid, &stat, 0);
|
||||||
|
assert(stat == 0);
|
||||||
|
return 0;
|
||||||
|
failed:;
|
||||||
|
kTEST("mutex test case1 failed.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ktest_case_table kt_mutex_func_table[] = {
|
||||||
|
ktest_mutex_case0,
|
||||||
|
ktest_mutex_case1,
|
||||||
|
};
|
||||||
|
uint64_t ktest_test_mutex(uint64_t arg)
|
||||||
|
{
|
||||||
|
kTEST("Testing mutex...");
|
||||||
|
mutex_init(&mtx);
|
||||||
|
|
||||||
|
for (int i = 0; i < sizeof(kt_mutex_func_table) / sizeof(ktest_case_table); ++i)
|
||||||
|
{
|
||||||
|
kTEST("Testing case %d", i);
|
||||||
|
kt_mutex_func_table[i](i, 0);
|
||||||
|
}
|
||||||
|
kTEST("mutex Test done.");
|
||||||
|
return 0;
|
||||||
|
}
|
@ -6,6 +6,7 @@
|
|||||||
#include <common/compiler.h>
|
#include <common/compiler.h>
|
||||||
#include <common/libELF/elf.h>
|
#include <common/libELF/elf.h>
|
||||||
#include <common/time.h>
|
#include <common/time.h>
|
||||||
|
#include <common/sys/wait.h>
|
||||||
#include <driver/video/video.h>
|
#include <driver/video/video.h>
|
||||||
#include <driver/usb/usb.h>
|
#include <driver/usb/usb.h>
|
||||||
#include <exception/gate.h>
|
#include <exception/gate.h>
|
||||||
@ -416,8 +417,14 @@ ul initial_kernel_thread(ul arg)
|
|||||||
usb_init();
|
usb_init();
|
||||||
|
|
||||||
// 对一些组件进行单元测试
|
// 对一些组件进行单元测试
|
||||||
ktest_start(ktest_test_bitree, 0);
|
uint64_t tpid[] = {
|
||||||
ktest_start(ktest_test_kfifo, 0);
|
ktest_start(ktest_test_bitree, 0),
|
||||||
|
ktest_start(ktest_test_kfifo, 0),
|
||||||
|
ktest_start(ktest_test_mutex, 0),
|
||||||
|
};
|
||||||
|
// 等待测试进程退出
|
||||||
|
for(int i=0;i<sizeof(tpid)/sizeof(uint64_t);++i)
|
||||||
|
waitpid(tpid[i], NULL, NULL);
|
||||||
|
|
||||||
// 准备切换到用户态
|
// 准备切换到用户态
|
||||||
struct pt_regs *regs;
|
struct pt_regs *regs;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user