增加简单的sema&mutex支持

This commit is contained in:
zhangzheng
2024-08-07 22:51:57 +08:00
parent 1132f9997e
commit 74f3c6760a
20 changed files with 391 additions and 322 deletions

View File

@@ -150,6 +150,7 @@ static void other_cpu_boot(void)
arch_cpu_knl_init();
while (1)
{
cpu_sleep();
}
}
void dumpstack(void)

View File

@@ -139,6 +139,7 @@ typedef struct sp_info
#endif
} sp_info_t;
#define cpu_sleep() asm volatile("wfi" : : : "memory")
#define _barrier() __asm__ __volatile__("" : : : "memory")
#define _dmb(ins) \
asm volatile("dmb " #ins : : : "memory")

View File

@@ -38,6 +38,7 @@ enum knl_obj_type {
FUTEX_TYPE,
SHARE_MEM_TYPE,
VMAM_TYPE,
SEMA_TYPE,
};
/**
* @brief 以下信息用于调试

View File

@@ -26,6 +26,7 @@ enum kobj_prot
IRQ_PROT,
SHARE_MEM_PROT, // 10
VMA_PROT,
SEMA_PROT,
MAX_PROT,
};

32
mkrtos_knl/inc/knl/sema.h Normal file
View File

@@ -0,0 +1,32 @@
#pragma once
#include <spinlock.h>
#include <slist.h>
typedef struct sema
{
kobject_t kobj; //!< 内核对象节点
spinlock_t lock; //!<
int cnt; //!< 计数
int max_cnt; //!< 最大计数
slist_head_t suspend_head; //!< 挂起的线程
} sema_t;
typedef sema_t mutex_t;
void sema_init(sema_t *obj, int cnt, int max);
void sema_up(sema_t *obj);
void sema_down(sema_t *obj);
void mutex_init(mutex_t *lock)
{
sema_init(lock, 1, 1);
}
void mutex_lock(mutex_t *lock)
{
sema_down(lock);
}
void mutex_unlock(mutex_t *lock)
{
sema_up(lock);
}

View File

@@ -29,7 +29,7 @@
#define __WEAK__ __attribute__((weak))
#define container_of(ptr, type, member) \
((type *)(((umword_t)(ptr)) - ((umword_t)(&(((type *)0)->member)))))
((type *)(((unsigned long)(ptr)) - ((unsigned long)(&(((type *)0)->member)))))
#define USED __attribute__((used))

205
mkrtos_knl/knl/sema.c Normal file
View File

@@ -0,0 +1,205 @@
#include "types.h"
#include "kobject.h"
#include "spinlock.h"
#include "atomics.h"
#include "slist.h"
#include "thread.h"
#include "factory.h"
#include "sema.h"
#include "init.h"
#if IS_ENABLED(CONFIG_BUDDY_SLAB)
#include <slab.h>
static slab_t *sema_slab;
#endif
enum SEMA_OP
{
SEMA_UP,
SEMA_DOWN,
};
static void sema_mem_init(void)
{
#if IS_ENABLED(CONFIG_BUDDY_SLAB)
sema_slab = slab_create(sizeof(sema_t), "sema");
assert(sema_slab);
#endif
}
INIT_KOBJ_MEM(sema_mem_init);
typedef struct sema_wait_item
{
slist_head_t node;
thread_t *thread;
} sema_wait_item_t;
static void sema_wait_item_init(sema_wait_item_t *obj, thread_t *th)
{
slist_init(&obj->node);
obj->thread = th;
}
void sema_up(sema_t *obj)
{
assert(obj);
umword_t status;
status = spinlock_lock(&obj->lock);
if (slist_is_empty(&obj->suspend_head))
{
if (obj->cnt < obj->max_cnt)
{
obj->cnt++;
}
// printk("up0 sema cnt:%d max:%d.\n", obj->cnt, obj->max_cnt);
}
else
{
slist_head_t *first_wait_node;
sema_wait_item_t *first_wait;
first_wait_node = slist_first(&obj->suspend_head);
first_wait = container_of(first_wait_node, sema_wait_item_t, node);
slist_del(first_wait_node);
thread_ready_remote(first_wait->thread, FALSE);
if (obj->cnt < obj->max_cnt)
{
obj->cnt++;
}
// printk("up1 sema cnt:%d max:%d.\n", obj->cnt, obj->max_cnt);
}
spinlock_set(&obj->lock, status);
}
void sema_down(sema_t *obj)
{
assert(obj);
thread_t *th = thread_get_current();
umword_t status;
sema_wait_item_t wait_item;
again:
status = spinlock_lock(&obj->lock);
if (obj->cnt == 0)
{
sema_wait_item_init(&wait_item, th);
slist_add_append(&obj->suspend_head, &wait_item.node);
thread_suspend_sw(th, FALSE);
spinlock_set(&obj->lock, status);
goto again;
}
else
{
assert(obj->cnt > 0);
obj->cnt--;
// printk("down sema cnt:%d max:%d.\n", obj->cnt, obj->max_cnt);
}
spinlock_set(&obj->lock, status);
}
static void sema_syscall(kobject_t *kobj, syscall_prot_t sys_p,
msg_tag_t in_tag, entry_frame_t *f)
{
sema_t *sema = container_of(kobj, sema_t, kobj);
msg_tag_t tag = msg_tag_init4(0, 0, 0, -EINVAL);
task_t *task = thread_get_current_task();
if (sys_p.prot != SEMA_PROT)
{
f->regs[0] = msg_tag_init4(0, 0, 0, -EPROTO).raw;
return;
}
switch (sys_p.op)
{
case SEMA_UP:
{
sema_up(sema);
tag = msg_tag_init4(0, 0, 0, 0);
}
break;
case SEMA_DOWN:
{
sema_down(sema);
tag = msg_tag_init4(0, 0, 0, 0);
}
}
f->regs[0] = tag.raw;
}
static sema_t *sema_create(ram_limit_t *lim, umword_t cnt, umword_t max)
{
sema_t *kobj = NULL;
#if IS_ENABLED(CONFIG_BUDDY_SLAB)
kobj = mm_limit_alloc_slab(sema_slab, lim);
#else
kobj = mm_limit_alloc(lim, sizeof(factory_t));
#endif
if (!kobj)
{
return NULL;
}
sema_init(kobj, cnt, max);
return kobj;
}
static void sema_unmap(obj_space_t *obj_space, kobject_t *kobj)
{
}
static void sema_release_stage1(kobject_t *kobj)
{
/*TODO:*/
sema_t *sm = container_of(kobj, sema_t, kobj);
kobject_invalidate(kobj);
}
static void sema_release_stage2(kobject_t *kobj)
{
/*TODO:*/
printk("sema 0x%x free.\n", kobj);
}
void sema_init(sema_t *obj, int cnt, int max)
{
if (max <= 0)
{
max = 1;
}
if (cnt < 0)
{
cnt = 0;
}
if (cnt > max)
{
cnt = max;
}
obj->cnt = cnt;
kobject_init(&obj->kobj, SEMA_TYPE);
spinlock_init(&obj->lock);
slist_init(&obj->suspend_head);
obj->max_cnt = max <= 0 ? 1 : max;
obj->kobj.invoke_func = sema_syscall;
// obj->kobj.put_func = thread_put;
obj->kobj.stage_1_func = sema_release_stage1;
obj->kobj.stage_2_func = sema_release_stage2;
printk("sema init cnt:%d max:%d.\n", cnt, max);
}
static kobject_t *sema_func(ram_limit_t *lim, umword_t arg0, umword_t arg1,
umword_t arg2, umword_t arg3)
{
sema_t *sema = sema_create(lim, arg0, arg1);
if (!sema)
{
return NULL;
}
return &sema->kobj;
}
/**
* @brief 工厂注册函数
*
*/
static void sema_factory_register(void)
{
factory_register(sema_func, SEMA_PROT);
}
INIT_KOBJ(sema_factory_register);

View File

@@ -51,6 +51,7 @@ static void knl_main(void)
task_t *pos;
if (slist_is_empty(&del_task_head)) {
cpu_sleep();
continue;
}

View File

@@ -11,3 +11,4 @@ msg_tag_t factory_create_thread(obj_handler_t obj, vpage_t vpage);
msg_tag_t factory_create_thread_vcpu(obj_handler_t obj, vpage_t vpage);
msg_tag_t factory_create_task(obj_handler_t obj, vpage_t vpage);
msg_tag_t facotry_create_share_mem(obj_handler_t obj, vpage_t vpage, umword_t size);
msg_tag_t facotry_create_sema(obj_handler_t obj, vpage_t vpage, int cnt, int max);

View File

@@ -15,6 +15,7 @@ enum kobj_prot
IRQ_PROT,
SHARE_MEM_PROT, // 10
VMA_PROT,
SEMA_PROT,
MAX_PROT,
};

View File

@@ -0,0 +1,7 @@
#pragma once
#include "u_prot.h"
#include "u_hd_man.h"
msg_tag_t u_sema_up(obj_handler_t obj);
msg_tag_t u_sema_down(obj_handler_t obj);

View File

@@ -105,3 +105,22 @@ msg_tag_t facotry_create_share_mem(obj_handler_t obj, vpage_t vpage, umword_t si
return tag;
}
msg_tag_t facotry_create_sema(obj_handler_t obj, vpage_t vpage, int cnt, int max)
{
register volatile umword_t r0 asm(ARCH_REG_0);
mk_syscall(syscall_prot_create(FACTORY_CREATE_KOBJ, FACTORY_PROT, obj).raw,
0,
SEMA_PROT,
vpage.raw,
cnt,
max,
0);
asm __volatile__(""
:
:
: ARCH_REG_0);
msg_tag_t tag = msg_tag_init(r0);
return tag;
}

View File

@@ -0,0 +1,39 @@
#include "u_types.h"
#include "u_prot.h"
#include "u_arch.h"
enum SEMA_OP
{
SEMA_UP,
SEMA_DOWN,
};
msg_tag_t u_sema_up(obj_handler_t obj)
{
register volatile umword_t r0 asm(ARCH_REG_0);
mk_syscall(syscall_prot_create(SEMA_UP, SEMA_PROT, obj).raw,
0,
0,
0,
0,
0,
0);
msg_tag_t tag = msg_tag_init(r0);
return tag;
}
msg_tag_t u_sema_down(obj_handler_t obj)
{
register volatile umword_t r0 asm(ARCH_REG_0);
mk_syscall(syscall_prot_create(SEMA_DOWN, SEMA_PROT, obj).raw,
0,
0,
0,
0,
0,
0);
msg_tag_t tag = msg_tag_init(r0);
return tag;
}

View File

@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.13)
file(GLOB deps src/*.c src/*.S)
file(GLOB deps src/*.c src/*.S src/test/*.c)
file(GLOB arch_src src/test/${ARCH_NAME}/*.c src/test/${ARCH_NAME}/*.S)
add_executable(init.elf

View File

@@ -36,6 +36,8 @@
static void test(void)
{
#if 0
u_sema_test();
u_sema_test2();
ipi_test();
ipc_test();
ipc_test2();

View File

@@ -1,197 +0,0 @@
#include "u_log.h"
#include "u_prot.h"
#include "u_mm.h"
#include "u_factory.h"
#include "u_thread.h"
#include "u_task.h"
#include "u_ipc.h"
#include "u_hd_man.h"
#include "u_task.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <u_sleep.h>
#include <stdlib.h>
#define DEBUG_IPC_CALL 1
//! 读取系统寄存器
#define read_sysreg(reg) ({ \
unsigned long _val; \
asm volatile("mrs %0, " #reg \
: "=r"(_val)); \
_val; \
})
static inline int get_cpu_id(void)
{
return read_sysreg(mpidr_el1) & 0xff; // 读取该寄存器获取处理器id
}
static umword_t th1_hd = 0;
static umword_t th2_hd = 0;
static umword_t th3_hd = 0;
static umword_t th4_hd = 0;
static __attribute__((aligned(4096))) char msg_buf0[4096];
static __attribute__((aligned(4096))) char msg_buf1[4096];
static __attribute__((aligned(4096))) char msg_buf2[4096];
static __attribute__((aligned(4096))) char msg_buf3[4096];
#define STACK_SIZE 2048
static __attribute__((aligned(8))) uint8_t stack0[STACK_SIZE];
static __attribute__((aligned(8))) uint8_t stack1[STACK_SIZE];
static __attribute__((aligned(8))) uint8_t stack2[STACK_SIZE];
static __attribute__((aligned(8))) uint8_t stack3[STACK_SIZE];
static void hard_sleep(void)
{
for (volatile int i; i < 10000000; i++)
;
}
static int test_cn = 0;
static int to_cpu[4];
static void thread_test_func(void)
{
char *buf;
umword_t len;
printf("%s:%d thread 0 init.\n", __func__, __LINE__);
while (1)
{
to_cpu[0] = rand() % 4;
printf("thread 0 to %d cpu.\n", to_cpu[0]);
thread_run_cpu(th1_hd, 2, to_cpu[0]);
assert(to_cpu[0] == get_cpu_id());
test_cn++;
}
}
static void thread_test_func2(void)
{
char *buf;
umword_t len;
printf("%s:%d thread 1 init.\n", __func__, __LINE__);
while (1)
{
to_cpu[1] = rand() % 4;
printf("thread 1 to %d cpu.\n", to_cpu[1]);
thread_run_cpu(th2_hd, 2, to_cpu[1]);
assert(to_cpu[1] == get_cpu_id());
test_cn++;
}
}
static void thread_test_func3(void)
{
printf("%s:%d thread 2 init.\n", __func__, __LINE__);
while (1)
{
to_cpu[2] = rand() % 4;
printf("thread 2 to %d cpu.\n", to_cpu[2]);
thread_run_cpu(th3_hd, 2, to_cpu[2]);
assert(to_cpu[2] == get_cpu_id());
test_cn++;
}
}
static void thread_test_func4(void)
{
printf("%s:%d thread 3 init.\n", __func__, __LINE__);
while (1)
{
to_cpu[3] = rand() % 4;
printf("thread 3 to %d cpu.\n", to_cpu[3]);
thread_run_cpu(th4_hd, 2, to_cpu[3]);
assert(to_cpu[3] == get_cpu_id());
test_cn++;
}
}
/**
* @brief 启动两个线程并进行ipc测试
*
*/
void ipi_test(void)
{
msg_tag_t tag;
th1_hd = handler_alloc();
assert(th1_hd != HANDLER_INVALID);
th2_hd = handler_alloc();
assert(th2_hd != HANDLER_INVALID);
th3_hd = handler_alloc();
assert(th3_hd != HANDLER_INVALID);
memset(msg_buf0, 0, sizeof(msg_buf0));
memset(msg_buf1, 0, sizeof(msg_buf1));
memset(msg_buf2, 0, sizeof(msg_buf2));
memset(msg_buf3, 0, sizeof(msg_buf3));
tag = factory_create_thread(FACTORY_PROT, vpage_create_raw3(KOBJ_ALL_RIGHTS, 0, th1_hd));
assert(msg_tag_get_prot(tag) >= 0);
tag = thread_bind_task(th1_hd, TASK_THIS);
assert(msg_tag_get_prot(tag) >= 0);
tag = thread_msg_buf_set(th1_hd, msg_buf0);
assert(msg_tag_get_prot(tag) >= 0);
tag = thread_exec_regs(th1_hd, (umword_t)thread_test_func, (umword_t)stack0 + STACK_SIZE, TASK_RAM_BASE(), 0);
task_set_obj_name(TASK_THIS, th1_hd, "cli_th");
assert(msg_tag_get_prot(tag) >= 0);
tag = thread_run_cpu(th1_hd, 2, 0);
assert(msg_tag_get_prot(tag) >= 0);
assert(msg_tag_get_prot(tag) >= 0);
tag = factory_create_thread(FACTORY_PROT, vpage_create_raw3(KOBJ_ALL_RIGHTS, 0, th2_hd));
assert(msg_tag_get_prot(tag) >= 0);
tag = thread_bind_task(th2_hd, TASK_THIS);
assert(msg_tag_get_prot(tag) >= 0);
tag = thread_msg_buf_set(th2_hd, msg_buf1);
assert(msg_tag_get_prot(tag) >= 0);
tag = thread_exec_regs(th2_hd, (umword_t)thread_test_func2, (umword_t)stack1 + STACK_SIZE, TASK_RAM_BASE(), 0);
assert(msg_tag_get_prot(tag) >= 0);
task_set_obj_name(TASK_THIS, th2_hd, "cli0_th");
assert(msg_tag_get_prot(tag) >= 0);
tag = thread_run_cpu(th2_hd, 2, 0);
tag = factory_create_thread(FACTORY_PROT, vpage_create_raw3(KOBJ_ALL_RIGHTS, 0, th3_hd));
assert(msg_tag_get_prot(tag) >= 0);
tag = thread_bind_task(th3_hd, TASK_THIS);
assert(msg_tag_get_prot(tag) >= 0);
tag = thread_msg_buf_set(th3_hd, msg_buf2);
assert(msg_tag_get_prot(tag) >= 0);
tag = thread_exec_regs(th3_hd, (umword_t)thread_test_func3, (umword_t)stack2 + STACK_SIZE, TASK_RAM_BASE(), 0);
assert(msg_tag_get_prot(tag) >= 0);
task_set_obj_name(TASK_THIS, th3_hd, "cli1_th");
assert(msg_tag_get_prot(tag) >= 0);
tag = thread_run_cpu(th3_hd, 2, 0);
tag = factory_create_thread(FACTORY_PROT, vpage_create_raw3(KOBJ_ALL_RIGHTS, 0, th4_hd));
assert(msg_tag_get_prot(tag) >= 0);
tag = thread_bind_task(th4_hd, TASK_THIS);
assert(msg_tag_get_prot(tag) >= 0);
tag = thread_msg_buf_set(th4_hd, msg_buf3);
assert(msg_tag_get_prot(tag) >= 0);
tag = thread_exec_regs(th4_hd, (umword_t)thread_test_func4, (umword_t)stack3 + STACK_SIZE, TASK_RAM_BASE(), 0);
assert(msg_tag_get_prot(tag) >= 0);
task_set_obj_name(TASK_THIS, th4_hd, "cli2_th");
assert(msg_tag_get_prot(tag) >= 0);
tag = thread_run_cpu(th4_hd, 2, 0);
while (test_cn < 1000)
;
// task_unmap(TASK_THIS, vpage_create_raw3(KOBJ_DELETE_RIGHT, 0, th1_hd));
// task_unmap(TASK_THIS, vpage_create_raw3(KOBJ_DELETE_RIGHT, 0, th2_hd));
// task_unmap(TASK_THIS, vpage_create_raw3(KOBJ_DELETE_RIGHT, 0, th3_hd));
// task_unmap(TASK_THIS, vpage_create_raw3(KOBJ_DELETE_RIGHT, 0, th4_hd));
}

View File

@@ -0,0 +1,76 @@
#include "u_factory.h"
#include "u_sema.h"
#include "u_hd_man.h"
#include "u_task.h"
#include <assert.h>
#include <pthread.h>
#include <stdio.h>
int u_sema_test(void)
{
msg_tag_t tag;
obj_handler_t sema_hd;
sema_hd = handler_alloc();
assert(sema_hd != HANDLER_INVALID);
tag = facotry_create_sema(FACTORY_PROT, vpage_create_raw3(KOBJ_ALL_RIGHTS, 0, sema_hd), 0, 1);
assert(msg_tag_get_val(tag) >= 0);
u_sema_up(sema_hd);
u_sema_down(sema_hd);
handler_free_umap(sema_hd);
return 0;
}
#include <u_sleep.h>
static pthread_t pth1;
static pthread_t pth2;
static pthread_t pth3;
static obj_handler_t sema_hd2;
static void *thread_th1(void *arg)
{
while (1)
{
printf("sema_up start\n");
u_sema_up(sema_hd2);
u_sleep_ms(100);
printf("sema_up end\n");
}
return NULL;
}
static void *thread_th2(void *arg)
{
while (1)
{
printf("sema_down start\n");
u_sema_down(sema_hd2);
u_sleep_ms(50);
printf("sema_down end\n");
}
return NULL;
}
static void *thread_th3(void *arg)
{
while (1)
{
printf("sema_down2 start\n");
u_sema_down(sema_hd2);
u_sleep_ms(50);
printf("sema_down2 end\n");
}
return NULL;
}
int u_sema_test2(void)
{
msg_tag_t tag;
sema_hd2 = handler_alloc();
assert(sema_hd2 != HANDLER_INVALID);
tag = facotry_create_sema(FACTORY_PROT,
vpage_create_raw3(KOBJ_ALL_RIGHTS, 0, sema_hd2), 0, 1);
assert(msg_tag_get_val(tag) >= 0);
pthread_create(&pth1, NULL, thread_th1, NULL);
pthread_create(&pth1, NULL, thread_th2, NULL);
pthread_create(&pth3, NULL, thread_th3, NULL);
}

View File

@@ -23,3 +23,5 @@ void malloc_test(void);
void thread_cpu_test(void);
int thread_vcpu_test(void);
void ipi_test(void);
int u_sema_test(void);
int u_sema_test2(void);

View File

@@ -1,52 +0,0 @@
.text
.global thread_vcpu_test_fn
.type thread_vcpu_test_fn,%function
thread_vcpu_test_fn:
//mrs x0, ttbr0_el1
mov x0,x0
tlbi vmalle1 // Invalidate local TLB
dsb nsh
mov x0, #0x30000000
msr vbar_el1, x0
mov x0, #0x40000000
msr ttbr0_el1, x0
msr ttbr1_el1, x0
isb
mov x0, #0
msr spsr_el1, x0
mov x0, #1
mrs x1, SCTLR_EL1
orr x1, x1, x0
msr SCTLR_EL1, x1
isb
ic iallu
dsb nsh
isb
mrs x0, CurrentEL
mov x0, #0
msr spsr_el1, x0
adr x0, el0_entry
// mov x0, #0x80000
msr elr_el1, x0
eret
el0_entry:
//mrs x0, sp_el0
mov x0, #0x10000000
str x1, [x0]
mrs x0, TTBR0_EL2
mov x0, x1
mov x0, x1
mov x0, x1
mov x0, x1
mov x0, x1
mov x0, x1
mov x0, x1
// wfe //!<
// wfi
b .

View File

@@ -1,71 +0,0 @@
#include <u_thread.h>
#include <u_hd_man.h>
#include <u_task.h>
#include <errno.h>
#include <u_prot.h>
#include <u_factory.h>
#include <u_vmam.h>
#include <string.h>
#define STACK_SIZE 4096
static __attribute__((aligned(8))) uint8_t stack0[STACK_SIZE];
extern void thread_vcpu_test_fn(void);
int thread_vcpu_test(void)
{
msg_tag_t tag;
obj_handler_t th1_hd;
umword_t msg_buf_addr;
int ret;
th1_hd = handler_alloc();
if (th1_hd == HANDLER_INVALID)
{
return -ENOENT;
}
tag = factory_create_thread_vcpu(FACTORY_PROT, vpage_create_raw3(KOBJ_ALL_RIGHTS, 0, th1_hd));
if (msg_tag_get_prot(tag) < 0)
{
handler_free(th1_hd);
return msg_tag_get_prot(tag);
}
tag = u_vmam_alloc(VMA_PROT, vma_addr_create(VPAGE_PROT_RW, 0, 0),
PAGE_SIZE, 0, (addr_t *)(&msg_buf_addr));
if (msg_tag_get_val(tag) < 0)
{
ret = msg_tag_get_val(tag);
goto end;
}
memset((void *)msg_buf_addr, 0, PAGE_SIZE);
tag = thread_exec_regs(th1_hd, (umword_t)thread_vcpu_test_fn,
(umword_t)stack0 + STACK_SIZE - sizeof(void *),
TASK_RAM_BASE(), 0);
if (msg_tag_get_prot(tag) < 0)
{
ret = msg_tag_get_prot(tag);
goto end_free_mm;
}
tag = thread_bind_task(th1_hd, TASK_THIS);
if (msg_tag_get_prot(tag) < 0)
{
goto end_free_mm;
}
tag = thread_msg_buf_set(th1_hd, (void *)msg_buf_addr);
if (msg_tag_get_prot(tag) < 0)
{
goto end_free_mm;
}
thread_run(th1_hd, 2); // 优先级默认为2
ret = 0;
goto end_ok;
end_free_mm:
u_vmam_free(VMA_PROT, msg_buf_addr, PAGE_SIZE);
end:
handler_free_umap(th1_hd);
end_ok:
return ret;
}