new: mutex

This commit is contained in:
fslongjin 2022-07-31 17:09:12 +08:00
parent b98a3679c9
commit 946bbef392
10 changed files with 332 additions and 6 deletions

View File

@ -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
View 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
View 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 -
*
* - 1mutex
* -
* - 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
View 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
View 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);

View File

@ -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

View File

@ -3,6 +3,7 @@
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 线

View File

@ -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
View 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;
}

View File

@ -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;