diff --git a/Ubiquitous/XiZi_AIoT/hardkernel/arch/arm/armv7-a/cortex-a9/core.h b/Ubiquitous/XiZi_AIoT/hardkernel/arch/arm/armv7-a/cortex-a9/core.h index 2115c3633..01c5623bf 100644 --- a/Ubiquitous/XiZi_AIoT/hardkernel/arch/arm/armv7-a/cortex-a9/core.h +++ b/Ubiquitous/XiZi_AIoT/hardkernel/arch/arm/armv7-a/cortex-a9/core.h @@ -74,7 +74,7 @@ Modification: #include "cortex_a9.h" -#define NR_CPU 1 +#define NR_CPU 4 __attribute__((always_inline, optimize("O0"))) static inline uint32_t user_mode() { diff --git a/Ubiquitous/XiZi_AIoT/hardkernel/hardkernel_init.c b/Ubiquitous/XiZi_AIoT/hardkernel/hardkernel_init.c index d2d0a6f14..bd8a76cea 100644 --- a/Ubiquitous/XiZi_AIoT/hardkernel/hardkernel_init.c +++ b/Ubiquitous/XiZi_AIoT/hardkernel/hardkernel_init.c @@ -129,7 +129,7 @@ static bool xizi_gpt_init() return false; } // register clock handler to intr - struct XiziTrapDriver* p_intr_driver = (struct XiziTrapDriver*)AchieveResource(&intr_driver_tag); + struct XiziTrapDriver* p_intr_driver = GetSysObject(struct XiziTrapDriver, &intr_driver_tag); p_intr_driver->bind_irq_handler(p_clock_driver->get_clock_int(), xizi_clock_handler); p_intr_driver->single_irq_enable(p_clock_driver->get_clock_int(), 0, 0); return true; diff --git a/Ubiquitous/XiZi_AIoT/hardkernel/mmu/arm/armv7-a/cortex-a9/imx6q-sabrelite/memlayout.h b/Ubiquitous/XiZi_AIoT/hardkernel/mmu/arm/armv7-a/cortex-a9/imx6q-sabrelite/memlayout.h index 0a31e0241..1438f964c 100644 --- a/Ubiquitous/XiZi_AIoT/hardkernel/mmu/arm/armv7-a/cortex-a9/imx6q-sabrelite/memlayout.h +++ b/Ubiquitous/XiZi_AIoT/hardkernel/mmu/arm/armv7-a/cortex-a9/imx6q-sabrelite/memlayout.h @@ -73,4 +73,11 @@ Modification: #define KERN_MEM_BASE (0x90000000) // First kernel virtual address #define KERN_OFFSET (KERN_MEM_BASE - PHY_MEM_BASE) +/* virtual and physical addr translate */ +#define V2P(a) ((uint32_t)((uint32_t)(a)-KERN_OFFSET)) +#define P2V(a) ((void*)((void*)(a) + KERN_OFFSET)) + +#define V2P_WO(x) ((x)-KERN_OFFSET) // same as V2P, but without casts +#define P2V_WO(x) ((x) + KERN_OFFSET) // same as V2P, but without casts + // clang-format on diff --git a/Ubiquitous/XiZi_AIoT/hardkernel/mmu/arm/armv7-a/cortex-a9/include/mmu.h b/Ubiquitous/XiZi_AIoT/hardkernel/mmu/arm/armv7-a/cortex-a9/include/mmu.h index 7f5053d19..d5136d838 100644 --- a/Ubiquitous/XiZi_AIoT/hardkernel/mmu/arm/armv7-a/cortex-a9/include/mmu.h +++ b/Ubiquitous/XiZi_AIoT/hardkernel/mmu/arm/armv7-a/cortex-a9/include/mmu.h @@ -92,13 +92,6 @@ When the process switches, the flush TLB is no longer required anymore. #define CONTEXTIDR_R(val) __asm__ volatile("mrc p15, 0, %0, c13, c0, 1" : "=r"(val)) #define CONTEXTIDR_W(val) __asm__ volatile("mcr p15, 0, %0, c13, c0, 1" ::"r"(val)) -/* virtual and physical addr translate */ -#define V2P(a) ((uint32_t)((uint32_t)(a)-KERN_OFFSET)) -#define P2V(a) ((void*)((void*)(a) + KERN_OFFSET)) - -#define V2P_WO(x) ((x)-KERN_OFFSET) // same as V2P, but without casts -#define P2V_WO(x) ((x) + KERN_OFFSET) // same as V2P, but without casts - #ifndef __ASSEMBLER__ #include __attribute__((always_inline)) static inline uint32_t v2p(void* a) { return ((uint32_t)(a)) - KERN_MEM_BASE; } diff --git a/Ubiquitous/XiZi_AIoT/kernel_actracer/actracer.c b/Ubiquitous/XiZi_AIoT/kernel_actracer/actracer.c index f74596559..5985920e6 100644 --- a/Ubiquitous/XiZi_AIoT/kernel_actracer/actracer.c +++ b/Ubiquitous/XiZi_AIoT/kernel_actracer/actracer.c @@ -41,15 +41,16 @@ static void tracer_init_node(TracerNode* node, char* name, tracemeta_ac_type typ node->parent = NULL; if (name != NULL) { char* p_name = (char*)slab_alloc(&sys_tracer.node_name_allocator); - strcpy(p_name, name); - p_name[TRACER_NODE_NAME_LEN - 1] = '\0'; - node->name = p_name; - } - if (node->type == TRACER_OWNER) { - doubleListNodeInit(&node->children_guard); - } else { - node->p_resource = p_resource; + if (!p_name) { + p_name = "BAD_NAME(NOMEM)"; + } else { + strcpy(p_name, name); + p_name[TRACER_NODE_NAME_LEN - 1] = '\0'; + node->name = p_name; + } } + doubleListNodeInit(&node->children_guard); + node->p_resource = p_resource; doubleListNodeInit(&node->list_node); } @@ -58,16 +59,16 @@ void sys_tracer_init() // set sys_tracer resource identity tracer_init_node(&sys_tracer.root_node, NULL, TRACER_OWNER, NULL); sys_tracer.root_node.name = root_name; - sys_tracer.sys_tracer_tag.meta = &sys_tracer.root_node; + sys_tracer.sys_tracer_tag.inner_node = &sys_tracer.root_node; // init memory allocator - slab_init(&sys_tracer.node_allocator, sizeof(TracerNode)); - slab_init(&sys_tracer.node_name_allocator, sizeof(char[TRACER_NODE_NAME_LEN])); + slab_init(&sys_tracer.node_allocator, sizeof(TracerNode), "TracerNodeAllocator"); + slab_init(&sys_tracer.node_name_allocator, sizeof(char[TRACER_NODE_NAME_LEN]), "TracerNodeNameAllocator"); } static char* parse_path(char* path, char* const name) { - // skip extra '/' + // Skip extra '/' while (*path == '/') { path++; } @@ -75,21 +76,19 @@ static char* parse_path(char* path, char* const name) return NULL; } - // start of current name + // Start of current name char* cur_start = path; while (*path != '/' && *path != '\0') { path++; } - // handle current name - int len = path - cur_start; + // Handle current name + size_t len = path - cur_start; if (len >= TRACER_NODE_NAME_LEN) { - strncpy(name, cur_start, TRACER_NODE_NAME_LEN); - name[TRACER_NODE_NAME_LEN - 1] = '\0'; - } else { - strncpy(name, cur_start, len); - name[len] = '\0'; + len = TRACER_NODE_NAME_LEN - 1; } + memcpy(name, cur_start, len); + name[len] = '\0'; return path; } @@ -121,39 +120,40 @@ bool AchieveResourceTag(TraceTag* target, TraceTag* owner, char* name) { static char name_buffer[TRACER_NODE_NAME_LEN]; - TracerNode* inner_node = owner->meta; + TracerNode* inner_node = owner->inner_node; assert(inner_node != NULL && inner_node->type == TRACER_OWNER); while ((name = parse_path(name, name_buffer)) != NULL) { if ((inner_node = tracer_find_node_onestep(inner_node, name_buffer)) == NULL) { DEBUG("Tracer: No such object, owner: %s, child: %s\n", // - owner->meta->name == NULL ? "NULL" : owner->meta->name, name == NULL ? "NULL" : name_buffer); + owner->inner_node->name == NULL ? "NULL" : owner->inner_node->name, name == NULL ? "NULL" : name_buffer); return false; } } - target->meta = inner_node; + target->inner_node = inner_node; return true; } void* AchieveResource(TraceTag* tag) { assert(tag != NULL); - if (tag->meta == NULL || tag->meta->type == TRACER_OWNER) { + if (tag->inner_node == NULL || tag->inner_node->type == TRACER_OWNER) { return NULL; } - return tag->meta->p_resource; + return tag->inner_node->p_resource; } bool CreateResourceTag(TraceTag* new_tag, TraceTag* owner, char* name, tracemeta_ac_type type, void* p_resource) { assert(owner != NULL); - if (owner->meta == NULL) { - ERROR("Tracer: Empty owner\n"); + if (owner->inner_node == NULL) { + ERROR("Tracer: Empty owner, node name: %s\n", name); return false; } - assert(owner->meta->type == TRACER_OWNER); - if (tracer_find_node_onestep(owner->meta, name) != NULL) { + // assert(owner->inner_node->type == TRACER_OWNER); + if (type == TRACER_SERVER_IDENTITY_AC_RESOURCE && // + tracer_find_node_onestep(owner->inner_node, name) != NULL) { return false; } @@ -165,11 +165,11 @@ bool CreateResourceTag(TraceTag* new_tag, TraceTag* owner, char* name, tracemeta tracer_init_node(new_node, name, type, p_resource); // new node add to owner's children list - doubleListAddOnHead(&new_node->list_node, &owner->meta->children_guard); - new_node->parent = owner->meta; + doubleListAddOnHead(&new_node->list_node, &owner->inner_node->children_guard); + new_node->parent = owner->inner_node; if (new_tag != NULL) { - new_tag->meta = new_node; + new_tag->inner_node = new_node; } return true; } @@ -177,54 +177,64 @@ bool CreateResourceTag(TraceTag* new_tag, TraceTag* owner, char* name, tracemeta bool DeleteResource(TraceTag* target, TraceTag* owner) { assert(target != NULL && owner != NULL); - assert(owner->meta != NULL && owner->meta->type == TRACER_OWNER); - if (target->meta == NULL) { - ERROR("Tracer: Delete a empty resource\n"); + assert(owner->inner_node != NULL && owner->inner_node->type == TRACER_OWNER); + if (target->inner_node == NULL) { + ERROR("Tracer: Delete a empty resource, owner: %s\n", owner->inner_node->name); return false; } - assert(target->meta->parent == owner->meta); - doubleListDel(&target->meta->list_node); + assert(target->inner_node->parent == owner->inner_node); + doubleListDel(&target->inner_node->list_node); // delete name - if (target->meta->name != NULL) { - slab_free(&sys_tracer.node_name_allocator, target->meta->name); + if (target->inner_node->name != NULL) { + slab_free(&sys_tracer.node_name_allocator, target->inner_node->name); } // delete all children - if (target->meta->type == TRACER_OWNER) { - while (!IS_DOUBLE_LIST_EMPTY(&target->meta->children_guard)) { + if (target->inner_node->type == TRACER_OWNER) { + while (!IS_DOUBLE_LIST_EMPTY(&target->inner_node->children_guard)) { TraceTag tmp_node = { - .meta = DOUBLE_LIST_ENTRY(target->meta->children_guard.next, TracerNode, list_node), + .inner_node = DOUBLE_LIST_ENTRY(target->inner_node->children_guard.next, TracerNode, list_node), }; DeleteResource(&tmp_node, target); } } - slab_free(&sys_tracer.node_allocator, target->meta); - target->meta = NULL; + slab_free(&sys_tracer.node_allocator, target->inner_node); + target->inner_node = NULL; return true; } -void debug_list_tracetree_inner(TracerNode* cur_node) +#define debug_print_blanks(n) \ + for (int __i = 0; __i < n; __i++) { \ + DEBUG_PRINTF(" "); \ + } + +void debug_list_tracetree_inner(TracerNode* cur_node, int nr_blanks) { - DEBUG("[%s] ", cur_node->name); + debug_print_blanks(nr_blanks); + if (cur_node->name == NULL) { + DEBUG_PRINTF("[ANON %d] ", cur_node->type); + } else { + DEBUG_PRINTF("[%s %d] ", cur_node->name, cur_node->type); + } TracerNode* tmp = NULL; DOUBLE_LIST_FOR_EACH_ENTRY(tmp, &cur_node->children_guard, list_node) { if (tmp->name != NULL) { - DEBUG("%s ", tmp->name); + DEBUG_PRINTF("%s ", tmp->name); } else { - DEBUG("ANON "); + DEBUG_PRINTF("ANON "); } } - DEBUG("\n"); + DEBUG_PRINTF("\n"); DOUBLE_LIST_FOR_EACH_ENTRY(tmp, &cur_node->children_guard, list_node) { - debug_list_tracetree_inner(tmp); + debug_list_tracetree_inner(tmp, nr_blanks + 1); } } void debug_list_tracetree() { - TracerNode* ref_root = RequireRootTag()->meta; - debug_list_tracetree_inner(ref_root); + TracerNode* ref_root = RequireRootTag()->inner_node; + debug_list_tracetree_inner(ref_root, 0); } \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/kernel_actracer/actracer.h b/Ubiquitous/XiZi_AIoT/kernel_actracer/actracer.h index 06f819c6a..a2a9f3e0d 100644 --- a/Ubiquitous/XiZi_AIoT/kernel_actracer/actracer.h +++ b/Ubiquitous/XiZi_AIoT/kernel_actracer/actracer.h @@ -30,35 +30,12 @@ Modification: #include #include -#include "list.h" +#include "actracer_tag.h" #include "object_allocator.h" #define TRACER_NODE_NAME_LEN 32 -typedef enum { - TRACER_INVALID = 0, - TRACER_OWNER, - TRACER_HARDKERNEL_AC_RESOURCE, - TRACER_TASK_DESCRIPTOR_AC_RESOURCE, - TRACER_SERVER_IDENTITY_AC_RESOURCE, - TRACER_MEM_FROM_BUDDY_AC_RESOURCE, -} tracemeta_ac_type; - -typedef struct TracerNode { - tracemeta_ac_type type; - char* name; - union { - struct double_list_node children_guard; - void* p_resource; - }; - struct TracerNode* parent; - struct double_list_node list_node; -} TracerNode; - -/// @brief tag for other module to reference trace meta -typedef struct TraceTag { - TracerNode* meta; -} TraceTag; +#define GetSysObject(type, target_tag) (type*)AchieveResource(target_tag) struct SysTracer { TracerNode root_node; @@ -72,4 +49,6 @@ TraceTag* const RequireRootTag(); bool AchieveResourceTag(struct TraceTag* target, struct TraceTag* owner, char* name); void* AchieveResource(struct TraceTag* tag); bool CreateResourceTag(struct TraceTag* new_tag, struct TraceTag* owner, char* name, tracemeta_ac_type type, void* p_resource); -bool DeleteResource(struct TraceTag* target, struct TraceTag* owner); \ No newline at end of file +bool DeleteResource(struct TraceTag* target, struct TraceTag* owner); + +void debug_list_tracetree(); \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/kernel_actracer/actracer_tag.h b/Ubiquitous/XiZi_AIoT/kernel_actracer/actracer_tag.h new file mode 100644 index 000000000..7cb17f927 --- /dev/null +++ b/Ubiquitous/XiZi_AIoT/kernel_actracer/actracer_tag.h @@ -0,0 +1,27 @@ +#pragma once +#include "list.h" + +typedef enum { + TRACER_INVALID = 0, + TRACER_OWNER, + TRACER_HARDKERNEL_AC_RESOURCE, + TRACER_TASK_DESCRIPTOR_AC_RESOURCE, + TRACER_SERVER_IDENTITY_AC_RESOURCE, + TRACER_MEM_SIGNATURE, + TRACER_SYSOBJECT, +} tracemeta_ac_type; + +typedef struct TracerNode { + tracemeta_ac_type type; + char* name; + void* p_resource; + struct TracerNode* parent; + struct double_list_node list_node; + struct double_list_node children_guard; +} TracerNode; + +/// @brief tag for other module to reference trace inner_node +typedef struct TraceTag { + TracerNode* inner_node; + uint32_t authority; +} TraceTag; \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/services/app/Makefile b/Ubiquitous/XiZi_AIoT/services/app/Makefile index 98ee6c136..feda8c87b 100644 --- a/Ubiquitous/XiZi_AIoT/services/app/Makefile +++ b/Ubiquitous/XiZi_AIoT/services/app/Makefile @@ -69,6 +69,10 @@ epit_server: timer.o epit.o ccm_pll.o usyscall.o arch_usyscall.o libserial.o pri @${objdump} -S $@ > $@.asm endif +test_sleep: test_sleep.o libserial.o printf.o usyscall.o arch_usyscall.o + @${ld} ${user_ldflags} -e main -o $@ $^ ${board_specs} + @${objdump} -S $@ > $@.asm + test_semaphore: test_semaphore.o libserial.o printf.o usyscall.o arch_usyscall.o @${ld} ${user_ldflags} -e main -o $@ $^ ${board_specs} @${objdump} -S $@ > $@.asm diff --git a/Ubiquitous/XiZi_AIoT/services/app/test_sleep.c b/Ubiquitous/XiZi_AIoT/services/app/test_sleep.c new file mode 100644 index 000000000..16c02dd01 --- /dev/null +++ b/Ubiquitous/XiZi_AIoT/services/app/test_sleep.c @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2020 AIIT XUOS Lab + * XiUOS is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#include "libserial.h" +#include "usyscall.h" + +int main(int argc, char* argv[]) +{ + while (true) { + printf("sleep for 2 seconds\n"); + sleep(2000); + } + + exit(0); +} \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/services/drivers/Makefile b/Ubiquitous/XiZi_AIoT/services/drivers/Makefile index 00581353f..43e1ccc3c 100644 --- a/Ubiquitous/XiZi_AIoT/services/drivers/Makefile +++ b/Ubiquitous/XiZi_AIoT/services/drivers/Makefile @@ -1,4 +1,8 @@ -SRC_DIR := $(BOARD) usb +SRC_DIR := $(BOARD) + +ifeq ($(BOARD), 3568) +SRC_DIR += usb +endif include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiZi_AIoT/services/lib/ipc/libipc.c b/Ubiquitous/XiZi_AIoT/services/lib/ipc/libipc.c index 0ff25461f..27fe4d687 100644 --- a/Ubiquitous/XiZi_AIoT/services/lib/ipc/libipc.c +++ b/Ubiquitous/XiZi_AIoT/services/lib/ipc/libipc.c @@ -131,14 +131,14 @@ bool ipc_msg_get_nth_arg(struct IpcMsg* msg, const int arg_num, void* data, cons return true; } -void ipc_msg_send_wait(struct IpcMsg* msg) +void ipc_msg_send_wait(struct Session* session, struct IpcMsg* msg) { msg->header.magic = IPC_MSG_MAGIC; msg->header.valid = 1; msg->header.done = 0; while (msg->header.done == 0) { /// @todo syscall yield with prio decrease - yield(SYS_TASK_YIELD_BLOCK_IPC); + wait_session_call(session); } assert(msg->header.done == 1); } @@ -155,7 +155,7 @@ int ipc_session_wait(struct Session* session) struct IpcMsg* msg = IPCSESSION_MSG(session); while (msg->header.done == 0) { /// @todo syscall yield with prio decrease - yield(SYS_TASK_YIELD_BLOCK_IPC); + wait_session_call(session); } assert(msg->header.done == 1); return msg->header.ret_val; diff --git a/Ubiquitous/XiZi_AIoT/services/lib/ipc/libipc.h b/Ubiquitous/XiZi_AIoT/services/lib/ipc/libipc.h index 82af08799..bdfb4e1f0 100644 --- a/Ubiquitous/XiZi_AIoT/services/lib/ipc/libipc.h +++ b/Ubiquitous/XiZi_AIoT/services/lib/ipc/libipc.h @@ -180,7 +180,7 @@ __attribute__((__always_inline__)) static inline bool ipc_session_forward(struct struct IpcMsg* new_ipc_msg(struct Session* session, const int argc, const int* arg_size); bool ipc_msg_set_nth_arg(struct IpcMsg* msg, const int arg_num, const void* const data, const int len); bool ipc_msg_get_nth_arg(struct IpcMsg* msg, const int arg_num, void* data, const int len); -void ipc_msg_send_wait(struct IpcMsg* msg); +void ipc_msg_send_wait(struct Session* session, struct IpcMsg* msg); void ipc_msg_send_nowait(struct IpcMsg* msg); int ipc_session_wait(struct Session* session); @@ -230,7 +230,7 @@ void ipc_server_loop(struct IpcNode* ipc_node); struct IpcMsg* msg = IPC_CREATE_MSG_FUNC(ipc_name)(session, _VA_FRONT_ARG##argc(__VA_ARGS__)); \ int ret = IPC_MSG_ARGS_COPY_SET_FUNC(ipc_name)(msg, _VA_FRONT_ARG##argc(__VA_ARGS__)); \ ret = ipc_msg_set_opcode(msg, ipc_name); \ - ipc_msg_send_wait(msg); \ + ipc_msg_send_wait(session, msg); \ ret = IPC_MSG_ARGS_COPY_GET_FUNC(ipc_name)(msg, _VA_FRONT_ARG##argc(__VA_ARGS__)); \ int32_t res = 0; \ ipc_msg_get_return(msg, &res); \ @@ -278,9 +278,10 @@ uintptr_t _ipc_buf_to_addr(char* buf); char addr_buf[17]; \ _ipc_addr_to_buf((uintptr_t)msg, addr_buf); \ char* param[] = { #ipc_name, addr_buf, NULL }; \ + msg->header.handling = 1; \ int tid = thread(IPC_THREAD_SERVE(ipc_name), #ipc_name, param); \ - if (tid > 0) { \ - msg->header.handling = 1; \ + if (tid <= 0) { \ + msg->header.handling = 0; \ } \ return 0; \ } diff --git a/Ubiquitous/XiZi_AIoT/services/lib/ipc/session.h b/Ubiquitous/XiZi_AIoT/services/lib/ipc/session.h index 196c6bf5b..0d655650e 100644 --- a/Ubiquitous/XiZi_AIoT/services/lib/ipc/session.h +++ b/Ubiquitous/XiZi_AIoT/services/lib/ipc/session.h @@ -36,7 +36,7 @@ Modification: #include "libserial.h" struct Session { - int id; + uintptr_t id; int capacity; int head; int tail; diff --git a/Ubiquitous/XiZi_AIoT/services/lib/usyscall/usyscall.c b/Ubiquitous/XiZi_AIoT/services/lib/usyscall/usyscall.c index 403d16e61..bca8ad7bb 100644 --- a/Ubiquitous/XiZi_AIoT/services/lib/usyscall/usyscall.c +++ b/Ubiquitous/XiZi_AIoT/services/lib/usyscall/usyscall.c @@ -72,6 +72,11 @@ int close_session(struct Session* session) return syscall(SYSCALL_CLOSE_SESSION, (intptr_t)session, 0, 0, 0); } +int wait_session_call(struct Session* userland_session) +{ + return syscall(SYSCALL_WAIT_SESSION, (intptr_t)userland_session, 0, 0, 0); +} + int get_memblock_info(sys_state_info* info) { return syscall(SYSCALL_SYS_STATE, SYS_STATE_MEMBLOCK_INFO, (intptr_t)info, 0, 0); @@ -102,6 +107,11 @@ int show_cpu() return syscall(SYSCALL_SYS_STATE, SYS_STATE_SHOW_CPU_INFO, 0, 0, 0); } +int show_actree() +{ + return syscall(SYSCALL_SYS_STATE, SYS_STATE_SHOW_ACTREE, 0, 0, 0); +} + uintptr_t get_second() { sys_state_info info; @@ -118,8 +128,12 @@ uintptr_t get_tick() uintptr_t mmap(uintptr_t vaddr, uintptr_t paddr, int len, bool is_dev) { + sys_mmap_info info = { + .type = SYS_MMAP_NORMAL, + .is_dev = is_dev, + }; uintptr_t vaddr_inner = vaddr, paddr_inner = paddr; - if (syscall(SYSCALL_MMAP, (intptr_t)&vaddr_inner, (intptr_t)&paddr_inner, (intptr_t)len, (intptr_t)is_dev) < 0) { + if (syscall(SYSCALL_MMAP, (intptr_t)&vaddr_inner, (intptr_t)&paddr_inner, (intptr_t)len, (intptr_t)&info) < 0) { return (uintptr_t)NULL; } return vaddr_inner; @@ -127,7 +141,30 @@ uintptr_t mmap(uintptr_t vaddr, uintptr_t paddr, int len, bool is_dev) int naive_mmap(uintptr_t* vaddr, uintptr_t* paddr, int len, bool is_dev) { - return syscall(SYSCALL_MMAP, (uintptr_t)vaddr, (intptr_t)paddr, (intptr_t)len, (intptr_t)is_dev); + sys_mmap_info info = { + .type = SYS_MMAP_NORMAL, + .is_dev = is_dev, + }; + return syscall(SYSCALL_MMAP, (uintptr_t)vaddr, (intptr_t)paddr, (intptr_t)len, (intptr_t)&info); +} + +int mmap_with_attr(uintptr_t vaddr, uintptr_t paddr, int len, uintptr_t attr) +{ + sys_mmap_info info = { + .type = SYS_MMAP_CUSTOMIZE, + .attr = attr, + }; + uintptr_t vaddr_inner = vaddr, paddr_inner = paddr; + return syscall(SYSCALL_MMAP, (intptr_t)&vaddr_inner, (intptr_t)&paddr_inner, (intptr_t)len, (intptr_t)&info); +} + +int naive_mmap_with_attr(uintptr_t* vaddr, uintptr_t* paddr, int len, uintptr_t attr) +{ + sys_mmap_info info = { + .type = SYS_MMAP_NORMAL, + .attr = attr, + }; + return syscall(SYSCALL_MMAP, (uintptr_t)vaddr, (intptr_t)paddr, (intptr_t)len, (intptr_t)&info); } int register_irq(int irq, int opcode) diff --git a/Ubiquitous/XiZi_AIoT/services/lib/usyscall/usyscall.h b/Ubiquitous/XiZi_AIoT/services/lib/usyscall/usyscall.h index de683f9cd..2a6815963 100644 --- a/Ubiquitous/XiZi_AIoT/services/lib/usyscall/usyscall.h +++ b/Ubiquitous/XiZi_AIoT/services/lib/usyscall/usyscall.h @@ -35,6 +35,8 @@ #define SYSCALL_SEMAPHORE 13 // semaphore related operations #define SYSCALL_SLEEP 14 // sleep + +#define SYSCALL_WAIT_SESSION 15 // clang-format on typedef enum { @@ -47,6 +49,7 @@ typedef enum { SYS_STATE_SHOW_CPU_INFO, SYS_STATE_GET_CURRENT_TICK, SYS_STATE_GET_CURRENT_SECOND, + SYS_STATE_SHOW_ACTREE, } sys_state_option; typedef enum { @@ -55,6 +58,17 @@ typedef enum { SYS_TASK_YIELD_BLOCK_IPC = 0x2, } task_yield_reason; +typedef enum { + SYS_MMAP_NORMAL = 0x0, + SYS_MMAP_CUSTOMIZE, +} sys_mmap_type; + +typedef struct sys_mmap_info { + sys_mmap_type type; + uintptr_t attr; + bool is_dev; +} sys_mmap_info; + typedef union { struct { uintptr_t memblock_start; @@ -86,12 +100,15 @@ int kill(int pid); int register_server(char* name); int session(char* path, int capacity, struct Session* user_session); -int poll_session(struct Session* userland_session_arr, int arr_capacity); +int poll_session(struct Session* userland_session, int arr_capacity); +int wait_session_call(struct Session* userland_session); int close_session(struct Session* session); int register_irq(int irq, int opcode); uintptr_t mmap(uintptr_t vaddr, uintptr_t paddr, int len, bool is_dev); int naive_mmap(uintptr_t* vaddr, uintptr_t* paddr, int len, bool is_dev); +int mmap_with_attr(uintptr_t vaddr, uintptr_t paddr, int len, uintptr_t attr); +int naive_mmap_with_attr(uintptr_t* vaddr, uintptr_t* paddr, int len, uintptr_t attr); int task_heap_base(); int get_memblock_info(sys_state_info* info); @@ -99,6 +116,10 @@ int set_priority(sys_state_info* info); int show_task(); int show_mem(); int show_cpu(); +int show_actree(); + +uintptr_t get_second(); +uintptr_t get_tick(); uintptr_t get_second(); uintptr_t get_tick(); diff --git a/Ubiquitous/XiZi_AIoT/services/shell/letter-shell/shell.c b/Ubiquitous/XiZi_AIoT/services/shell/letter-shell/shell.c index 34b99616e..dc34c4b73 100644 --- a/Ubiquitous/XiZi_AIoT/services/shell/letter-shell/shell.c +++ b/Ubiquitous/XiZi_AIoT/services/shell/letter-shell/shell.c @@ -1797,6 +1797,11 @@ void shellShowCpusInfo() show_cpu(); } +void shellShowActree() +{ + show_actree(); +} + #if SHELL_EXEC_UNDEF_FUNC == 1 /** * @brief shell执行未定义函数 diff --git a/Ubiquitous/XiZi_AIoT/services/shell/letter-shell/shell_cmd_list.c b/Ubiquitous/XiZi_AIoT/services/shell/letter-shell/shell_cmd_list.c index 762abed40..848555729 100644 --- a/Ubiquitous/XiZi_AIoT/services/shell/letter-shell/shell_cmd_list.c +++ b/Ubiquitous/XiZi_AIoT/services/shell/letter-shell/shell_cmd_list.c @@ -40,6 +40,7 @@ extern void shellKill(int pid); extern void shellShowTasks(); extern void shellShowMemInfo(); extern void shellShowCpusInfo(); +extern void shellShowActree(); #if SHELL_EXEC_UNDEF_FUNC == 1 extern int shellExecute(int argc, char* argv[]); @@ -118,6 +119,8 @@ const ShellCommand shellCommandList[] = { showMemInfo, shellShowMemInfo, display memory info), SHELL_CMD_ITEM(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC) | SHELL_CMD_DISABLE_RETURN, showCpusInfo, shellShowCpusInfo, display cpus info), + SHELL_CMD_ITEM(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC) | SHELL_CMD_DISABLE_RETURN, + showActree, shellShowActree, display actracer tree), #if SHELL_EXEC_UNDEF_FUNC == 1 SHELL_CMD_ITEM(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_DISABLE_RETURN, diff --git a/Ubiquitous/XiZi_AIoT/softkernel/Makefile b/Ubiquitous/XiZi_AIoT/softkernel/Makefile index 1464fe7b9..ba0bc8da0 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/Makefile +++ b/Ubiquitous/XiZi_AIoT/softkernel/Makefile @@ -1,4 +1,4 @@ -SRC_DIR := init memory trap task syscall +SRC_DIR := init memory trap task syscall tools SRC_FILES := main.c load_apps.S diff --git a/Ubiquitous/XiZi_AIoT/softkernel/include/assert.h b/Ubiquitous/XiZi_AIoT/softkernel/include/assert.h index 8d9d012be..81733ae11 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/include/assert.h +++ b/Ubiquitous/XiZi_AIoT/softkernel/include/assert.h @@ -41,3 +41,5 @@ extern void panic(char*); #define LIKELY(exp) __builtin_expect(exp, 1) #define UNLIKELY(exp) __builtin_expect(exp, 0) + +#define ERROR_FREE diff --git a/Ubiquitous/XiZi_AIoT/softkernel/include/bitmap64.h b/Ubiquitous/XiZi_AIoT/softkernel/include/bitmap64.h index 77f45e1da..8dbe85790 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/include/bitmap64.h +++ b/Ubiquitous/XiZi_AIoT/softkernel/include/bitmap64.h @@ -46,22 +46,23 @@ static inline void bitmap64_init(struct bitmap64* bitmap) static inline int bitmap64_alloc(struct bitmap64* bitmap) { int free_bit = -1; - // free bit is the first 0 bit, from [1, 64] + // free bit is the first 0 bit, from [0, 63] free_bit = __builtin_ffsl(~(uint64_t)(bitmap->map)); // handle if bitmap is full (no using 64th bit here) if (free_bit == 0) { return -1; } - assert(free_bit < 64 && free_bit >= 1); + free_bit -= 1; + assert(free_bit < 64 && free_bit >= 0); // alloc and return - bitmap->map |= (1 << (free_bit - 1)); - return free_bit - 1; + bitmap->map |= (1ULL << free_bit); + return free_bit; } static inline void bitmap64_free(struct bitmap64* bitmap, int idx) { // usages of bitmap64 must be correct - assert((bitmap->map & (1 << idx)) != 0); + assert((bitmap->map & (1ULL << idx)) != 0); // free bit - bitmap->map &= ~(uint64_t)(1 << idx); + bitmap->map &= ~(uint64_t)(1ULL << idx); } diff --git a/Ubiquitous/XiZi_AIoT/softkernel/include/buddy.h b/Ubiquitous/XiZi_AIoT/softkernel/include/buddy.h index 4b73e7cd4..65f796af6 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/include/buddy.h +++ b/Ubiquitous/XiZi_AIoT/softkernel/include/buddy.h @@ -31,7 +31,6 @@ Modification: #include "list.h" #include "memlayout.h" -#include "spinlock.h" #include #include @@ -70,7 +69,6 @@ struct KFreeList { struct KBuddy { uintptr_t n_pages; uintptr_t use_lock; - struct spinlock lock; struct KFreeList free_list[MAX_BUDDY_ORDER]; struct KPage* first_page; uintptr_t mem_start; diff --git a/Ubiquitous/XiZi_AIoT/softkernel/include/kalloc.h b/Ubiquitous/XiZi_AIoT/softkernel/include/kalloc.h index 66ec4cddd..8b8d70771 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/include/kalloc.h +++ b/Ubiquitous/XiZi_AIoT/softkernel/include/kalloc.h @@ -29,15 +29,26 @@ Modification: *************************************************/ #pragma once -#include "pagetable.h" +#include "actracer.h" +#include "rbtree.h" + +struct MemUsage { + TraceTag tag; + RbtTree mem_block_map; +}; bool module_phymem_init(); char* kalloc(size_t size); bool kfree(char* vaddr); bool raw_kfree(char* paddr); +void* kalloc_by_ownership(TraceTag owner, uintptr_t size); +bool kfree_by_ownership(TraceTag owner, void* vaddr); + char* raw_alloc(size_t size); bool raw_free(char* paddr); +void* raw_alloc_by_ownership(TraceTag owner, uintptr_t size); +bool raw_free_by_ownership(TraceTag owner, void* vaddr); void show_phymem_info(); diff --git a/Ubiquitous/XiZi_AIoT/softkernel/include/ksemaphore.h b/Ubiquitous/XiZi_AIoT/softkernel/include/ksemaphore.h index 99efd6523..d30e6732a 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/include/ksemaphore.h +++ b/Ubiquitous/XiZi_AIoT/softkernel/include/ksemaphore.h @@ -23,6 +23,14 @@ #include "list.h" #include "object_allocator.h" +#include "rbtree.h" + +typedef uintptr_t sem_id_t; +typedef int32_t sem_val_t; + +enum { + INVALID_SEM_ID = 0, +}; /// @warning this is no in use enum { @@ -30,8 +38,8 @@ enum { }; struct ksemaphore { - uint32_t id; - int val; + sem_id_t id; + sem_val_t val; /* list of waiting threads */ struct double_list_node wait_list_guard; /* list to manage semaphores */ @@ -40,12 +48,17 @@ struct ksemaphore { }; struct XiziSemaphorePool { - uint32_t next_sem_id; + sem_id_t next_sem_id; struct slab_allocator allocator; struct double_list_node sem_list_guard; + RbtTree sem_pool_map; + sem_val_t nr_sem; }; void semaphore_pool_init(struct XiziSemaphorePool* sem_pool); -int ksemaphore_alloc(struct XiziSemaphorePool* sem_pool, int val); -bool ksemaphore_free(struct XiziSemaphorePool* sem_pool, uint32_t sem_id); -bool ksemaphore_signal(struct XiziSemaphorePool* sem_pool, uint32_t sem_id); +sem_id_t ksemaphore_alloc(struct XiziSemaphorePool* sem_pool, sem_val_t val); +bool ksemaphore_free(struct XiziSemaphorePool* sem_pool, sem_id_t sem_id); +bool ksemaphore_signal(struct XiziSemaphorePool* sem_pool, sem_id_t sem_id); +bool ksemaphore_signal_no_wake(struct XiziSemaphorePool* sem_pool, sem_id_t sem_id); + +bool ksemaphore_consume(struct XiziSemaphorePool* sem_pool, sem_id_t sem_id, sem_val_t decre); diff --git a/Ubiquitous/XiZi_AIoT/softkernel/include/memspace.h b/Ubiquitous/XiZi_AIoT/softkernel/include/memspace.h index 44cc9575c..06d8732fb 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/include/memspace.h +++ b/Ubiquitous/XiZi_AIoT/softkernel/include/memspace.h @@ -32,6 +32,7 @@ Modification: #include "actracer.h" #include "bitmap64.h" #include "buddy.h" +#include "kalloc.h" #include "list.h" struct TopLevelPageDirectory { @@ -48,6 +49,11 @@ struct ThreadStackPointer { struct MemSpace { /* trace node */ TraceTag tag; + /* mem usage info */ + struct MemUsage kernspace_mem_usage; + struct MemUsage userspace_mem_usage; + struct MemUsage customized_mapping_mem_map; + /* task memory resources */ struct TopLevelPageDirectory pgdir; // [phy] vm pgtbl base address uintptr_t heap_base; // mem size of proc used(allocated by kernel) @@ -63,7 +69,7 @@ struct MemSpace { struct Thread* thread_to_notify; }; -struct MemSpace* alloc_memspace(); +struct MemSpace* alloc_memspace(char* name); void free_memspace(struct MemSpace* pmemspace); uintptr_t* load_memspace(struct MemSpace* pmemspace, char* img_start); -struct ThreadStackPointer load_user_stack(struct MemSpace* pmemspace, char** argv); \ No newline at end of file +struct ThreadStackPointer load_user_stack(struct MemSpace* pmemspace, char** argv); diff --git a/Ubiquitous/XiZi_AIoT/softkernel/include/object_allocator.h b/Ubiquitous/XiZi_AIoT/softkernel/include/object_allocator.h index a5865422a..52046905e 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/include/object_allocator.h +++ b/Ubiquitous/XiZi_AIoT/softkernel/include/object_allocator.h @@ -29,10 +29,12 @@ Modification: *************************************************/ #pragma once +#include "actracer_tag.h" #include #include struct slab_state { + TraceTag owner_tag; struct slab_state *prev, *next; uint64_t bitmap; uintptr_t refcount; @@ -45,9 +47,10 @@ struct slab_allocator { size_t slabsize; uint64_t bitmap_empty; struct slab_state *partial, *empty, *full; + char* name; }; -void slab_init(struct slab_allocator*, size_t); +void slab_init(struct slab_allocator*, size_t, char* name); void slab_destroy(const struct slab_allocator*); void* slab_alloc(struct slab_allocator*); diff --git a/Ubiquitous/XiZi_AIoT/softkernel/include/queue.h b/Ubiquitous/XiZi_AIoT/softkernel/include/queue.h new file mode 100644 index 000000000..c1b267ecb --- /dev/null +++ b/Ubiquitous/XiZi_AIoT/softkernel/include/queue.h @@ -0,0 +1,22 @@ +#pragma once +#include + +typedef struct QueueNode { + uintptr_t key; + void* data; + struct QueueNode* next; +} QueueNode; + +typedef struct Queue { + QueueNode* front; + QueueNode* rear; + int nr_ele; +} Queue; + +void queue_init(Queue* queue); +QueueNode* queue_front(Queue* queue); +bool queue_is_empty(Queue* queue); +bool dequeue(Queue* queue); +bool enqueue(Queue* queue, uintptr_t key, void* data); + +void module_queue_factory_init(TraceTag* _softkernel_tag); \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/softkernel/include/rbtree.h b/Ubiquitous/XiZi_AIoT/softkernel/include/rbtree.h new file mode 100644 index 000000000..0ffbdbe16 --- /dev/null +++ b/Ubiquitous/XiZi_AIoT/softkernel/include/rbtree.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include + +#include "actracer.h" + +// CLRS +// Insertion and Deletion in a Red Black Tree +enum rbt_type { + RED, + BLACK +}; + +typedef struct RbtNode { + uintptr_t key; + void* data; + struct RbtNode* left; + struct RbtNode* right; + struct RbtNode* parent; + enum rbt_type color; +} RbtNode; + +typedef struct RbtTree { + RbtNode* root; + int nr_ele; +} RbtTree; + +void rbtree_init(RbtTree* tree); +int rbt_insert(RbtTree* tree, uintptr_t key, void* data); +RbtNode* rbt_search(RbtTree* tree, uintptr_t key); +int rbt_delete(RbtTree* tree, uintptr_t key); + +void module_rbt_factory_init(TraceTag* _softkernel_tag); + +static inline bool rbt_is_empty(RbtTree* tree) +{ + return tree->nr_ele == 0; +} diff --git a/Ubiquitous/XiZi_AIoT/softkernel/include/schedule_algo.h b/Ubiquitous/XiZi_AIoT/softkernel/include/schedule_algo.h new file mode 100644 index 000000000..933731a5b --- /dev/null +++ b/Ubiquitous/XiZi_AIoT/softkernel/include/schedule_algo.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020 AIIT XUOS Lab + * XiUOS is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +/** + * @file scheduler.h + * @brief scheduler algorithm declaration + * @version 3.0 + * @author AIIT XUOS Lab + * @date 2023.08.25 + */ + +/************************************************* +File name: scheduler.h +Description: scheduler algorithm declaration +Others: +History: +1. Date: 2023-08-28 +Author: AIIT XUOS Lab +Modification: +1. first version +*************************************************/ +#pragma once + +#include "task.h" + +struct Thread* max_priority_runnable_task(void); +struct Thread* round_robin_runnable_task(uint32_t priority); +void recover_priority(void); \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/softkernel/include/scheduler.h b/Ubiquitous/XiZi_AIoT/softkernel/include/scheduler.h index 933731a5b..fbb3d03a9 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/include/scheduler.h +++ b/Ubiquitous/XiZi_AIoT/softkernel/include/scheduler.h @@ -1,36 +1,21 @@ -/* - * Copyright (c) 2020 AIIT XUOS Lab - * XiUOS is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ -/** - * @file scheduler.h - * @brief scheduler algorithm declaration - * @version 3.0 - * @author AIIT XUOS Lab - * @date 2023.08.25 - */ -/************************************************* -File name: scheduler.h -Description: scheduler algorithm declaration -Others: -History: -1. Date: 2023-08-28 -Author: AIIT XUOS Lab -Modification: -1. first version -*************************************************/ #pragma once +#include "actracer.h" +#include "ksemaphore.h" -#include "task.h" +#define TASK_MAX_PRIORITY 32 -struct Thread* max_priority_runnable_task(void); -struct Thread* round_robin_runnable_task(uint32_t priority); -void recover_priority(void); \ No newline at end of file +struct ScheduleNode { + TraceTag task_ref; + struct double_list_node list_node; +}; + +struct Scheduler { + TraceTag tag; + + struct double_list_node task_list_head[TASK_MAX_PRIORITY]; /* list of task control blocks that are allocated */ + struct double_list_node task_running_list_head; + struct double_list_node task_blocked_list_head; + struct double_list_node task_sleep_list_head; + struct XiziSemaphorePool semaphore_pool; +}; \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/softkernel/include/share_page.h b/Ubiquitous/XiZi_AIoT/softkernel/include/share_page.h index bcb90dde7..ff3f11a3a 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/include/share_page.h +++ b/Ubiquitous/XiZi_AIoT/softkernel/include/share_page.h @@ -32,12 +32,17 @@ Modification: #include #include "actracer.h" +#include "ksemaphore.h" #include "list.h" #include "task.h" +enum { + INVALID_SESS_ID = 0, +}; + /// @brief userland session info copy struct Session { - int id; + uintptr_t id; int capacity; int head; int tail; @@ -48,7 +53,7 @@ struct Session { #define CLIENT_SESSION_BACKEND(session) CONTAINER_OF(session, struct session_backend, client_side) struct server_session { - struct double_list_node node; // list_head of server task's ipc pipes + struct double_list_node node; // list node of server task's ipc pipes uintptr_t buf_addr; int capacity; int head; @@ -57,7 +62,7 @@ struct server_session { }; struct client_session { - struct double_list_node node; // list_head of client task's ipc pipes + struct double_list_node node; // list node of client task's ipc pipes uintptr_t buf_addr; int capacity; bool closed; @@ -67,11 +72,12 @@ struct client_session { struct session_backend { struct server_session server_side; struct client_session client_side; - int session_id; // id of this session + uintptr_t session_id; // id of this session int nr_pages; // pages used by this pipe struct Thread* client; // client of this pipe struct Thread* server; // server of this pipe + sem_id_t client_sem_to_wait; uintptr_t buf_kernel_addr; }; @@ -90,3 +96,6 @@ struct XiziSharePageManager { extern struct XiziSharePageManager xizi_share_page_manager; int module_share_page_init(struct SharePageRightGroup* right_group); + +void client_close_session(struct Thread* thd, struct client_session* cli_sess); +void server_close_session(struct Thread* thd, struct server_session* svr_sess); \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/softkernel/include/syscall.h b/Ubiquitous/XiZi_AIoT/softkernel/include/syscall.h index f2c0265d4..0749088b7 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/include/syscall.h +++ b/Ubiquitous/XiZi_AIoT/softkernel/include/syscall.h @@ -49,6 +49,8 @@ Modification: #define SYSCALL_SEMAPHORE 13 // semaphore related operations #define SYSCALL_SLEEP 14 // sleep + +#define SYSCALL_WAIT_SESSION 15 // clang-format on #ifndef __ASSEMBLER__ @@ -67,6 +69,7 @@ typedef enum { SYS_STATE_SHOW_CPU_INFO, SYS_STATE_GET_CURRENT_TICK, SYS_STATE_GET_CURRENT_SECOND, + SYS_STATE_SHOW_ACTREE, } sys_state_option; typedef enum { @@ -75,6 +78,17 @@ typedef enum { SYS_TASK_YIELD_BLOCK_IPC = 0x2, } task_yield_reason; +typedef enum { + SYS_MMAP_NORMAL = 0x0, + SYS_MMAP_CUSTOMIZE, +} sys_mmap_type; + +typedef struct { + sys_mmap_type type; + uintptr_t attr; + bool is_dev; +} sys_mmap_info; + typedef union { struct { uintptr_t memblock_start; @@ -104,10 +118,12 @@ int sys_register_as_server(char* name); int sys_connect_session(char* path, int capacity, struct Session* user_session); int sys_poll_session(struct Session* userland_session_arr, int arr_capacity); int sys_close_session(struct Thread* task, struct Session* session); +int sys_wait_session(struct Session* userland_session); int sys_exec(char* img_start, char* name, char** argv); int sys_state(sys_state_option option, sys_state_info* info); int sys_mmap(uintptr_t* vaddr, uintptr_t* paddr, int len, int is_dev); +int sys_mmap_v2(uintptr_t* vaddr, uintptr_t* paddr, int len, sys_mmap_info* info); int sys_register_irq(int irq_num, int irq_opcode); int sys_unbind_irq_all(struct Thread* task); diff --git a/Ubiquitous/XiZi_AIoT/softkernel/include/task.h b/Ubiquitous/XiZi_AIoT/softkernel/include/task.h index 096a0613e..158a8ef26 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/include/task.h +++ b/Ubiquitous/XiZi_AIoT/softkernel/include/task.h @@ -37,6 +37,7 @@ Modification: #include "memspace.h" #include "object_allocator.h" #include "pagetable.h" +#include "queue.h" #include "share_page.h" #include "spinlock.h" @@ -47,7 +48,8 @@ Modification: #define SLEEP_MONITOR_CORE 0 enum ProcState { - INIT = 0, + UNINIT = 0, + INIT, READY, RUNNING, DEAD, @@ -98,8 +100,12 @@ struct Thread { /* task communication resources */ struct double_list_node cli_sess_listhead; struct double_list_node svr_sess_listhead; + RbtTree cli_sess_map; + RbtTree svr_sess_map; + Queue sessions_to_be_handle; + Queue sessions_in_handle; struct TraceTag server_identifier; - bool advance_unblock; + bool advance_unblock; // @todo abandon /* task schedule attributes */ struct double_list_node node; @@ -115,6 +121,22 @@ struct SchedulerRightGroup { struct TraceTag mmu_driver_tag; }; +/* @todo task pool to maintain task lifetime and support fast task search */ +struct GlobalTaskPool { + RbtTree thd_ref_map; + struct double_list_node thd_listing_head; +}; + +struct TaskScheduler { +}; + +struct TaskLifecycleOperations { + /* new a task control block, checkout #sys_spawn for usage */ + struct Thread* (*new_thread)(struct MemSpace* pmemspace); + /* free a task control block, this calls #free_user_pgdir to free all vitual spaces */ + void (*free_thread)(struct Thread*); +}; + struct XiziTaskManager { TraceTag tag; /* thead schedule lists */ @@ -123,6 +145,10 @@ struct XiziTaskManager { struct double_list_node task_blocked_list_head; struct double_list_node task_sleep_list_head; struct XiziSemaphorePool semaphore_pool; + /* living task pool */ + TraceTag task_pool_tag; + /* task lifecycle Ops */ + TraceTag task_lifecycle_ops_tag; /* mem allocator */ struct slab_allocator memspace_allocator; @@ -132,10 +158,6 @@ struct XiziTaskManager { /* init task manager */ void (*init)(); - /* new a task control block, checkout #sys_spawn for usage */ - struct Thread* (*new_task_cb)(struct MemSpace* pmemspace); - /* free a task control block, this calls #free_user_pgdir to free all vitual spaces */ - void (*free_pcb)(struct Thread*); /* init a task control block, set name, remain_tick, state, cwd, priority, etc. */ void (*task_set_default_schedule_attr)(struct Thread*); diff --git a/Ubiquitous/XiZi_AIoT/softkernel/init/softkernel_init.c b/Ubiquitous/XiZi_AIoT/softkernel/init/softkernel_init.c index 53e3d4291..d10f5bac6 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/init/softkernel_init.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/init/softkernel_init.c @@ -31,10 +31,14 @@ Modification: #include "assert.h" #include "log.h" +#include "rbtree.h" #include "task.h" -bool softkernel_init(struct TraceTag* _hardkernel_tag, struct TraceTag* _softkernel_tag) +bool softkernel_init(TraceTag* _hardkernel_tag, struct TraceTag* _softkernel_tag) { + module_rbt_factory_init(_softkernel_tag); + module_queue_factory_init(_softkernel_tag); + struct TraceTag server_identifier_owner; CreateResourceTag(&server_identifier_owner, _softkernel_tag, "server-identifier", TRACER_OWNER, NULL); diff --git a/Ubiquitous/XiZi_AIoT/softkernel/main.c b/Ubiquitous/XiZi_AIoT/softkernel/main.c index d19f63d67..2528623e1 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/main.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/main.c @@ -59,6 +59,7 @@ int main(void) if (cpu_id == 0) { /* init memory management first */ + module_phymem_init(); // init buddy management system /* init tracer system */ sys_tracer_init(); diff --git a/Ubiquitous/XiZi_AIoT/softkernel/memory/buddy.c b/Ubiquitous/XiZi_AIoT/softkernel/memory/buddy.c index 97817851a..295889175 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/memory/buddy.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/memory/buddy.c @@ -31,6 +31,7 @@ Modification: #include "buddy.h" #include "kalloc.h" #include "log.h" +#include "pagetable.h" static void _buddy_split_page(struct KPage* page, uintptr_t low_order, uintptr_t high_order, struct KFreeList* list) { @@ -161,7 +162,8 @@ bool KBuddyInit(struct KBuddy* pbuddy, uintptr_t mem_start, uintptr_t mem_end) // total number of free pages pbuddy->n_pages = (pbuddy->mem_end - (uintptr_t)pbuddy->mem_start) >> LEVEL4_PTE_SHIFT; - memset(pbuddy->pages, 0, pbuddy->n_pages); + memset(pbuddy->pages, 0, pbuddy->n_pages * sizeof(struct KPage)); + // memset(pbuddy->pages, 0, pbuddy->n_pages); // init each free page list from 2^0 to 2^8 for (; i < MAX_BUDDY_ORDER; i++) { diff --git a/Ubiquitous/XiZi_AIoT/softkernel/memory/kalloc.c b/Ubiquitous/XiZi_AIoT/softkernel/memory/kalloc.c index 4bed55c1d..de0051162 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/memory/kalloc.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/memory/kalloc.c @@ -30,6 +30,9 @@ Modification: #include "kalloc.h" #include "assert.h" +#include "memlayout.h" +#include "pagetable.h" + #include "actracer.h" #include "buddy.h" @@ -64,11 +67,37 @@ char* kalloc(uintptr_t size) return mem_alloc; } +void* kalloc_by_ownership(TraceTag owner, uintptr_t size) +{ + void* new_mem = kalloc(size); + if (NULL == new_mem) { + return NULL; + } + + struct MemUsage* usage = GetSysObject(struct MemUsage, &owner); + if (0 != rbt_insert(&usage->mem_block_map, (uintptr_t)new_mem, NULL)) { + kfree(new_mem); + return NULL; + } + return new_mem; +} + bool kfree(char* vaddr) { return KBuddyFree(&kern_virtmem_buddy, V2P_WO(vaddr)); } +bool kfree_by_ownership(TraceTag owner, void* vaddr) +{ + struct MemUsage* usage = GetSysObject(struct MemUsage, &owner); + // DEBUG("%p %p %p %p\n", usage, usage->mem_block_root, usage->tag, vaddr); + RbtNode* node = rbt_search(&usage->mem_block_map, (uintptr_t)vaddr); + assert(NULL != node); + assert(0 == rbt_delete(&usage->mem_block_map, node->key)); + + return kfree(vaddr); +} + bool raw_kfree(char* paddr) { return KBuddyFree(&kern_virtmem_buddy, paddr); @@ -83,11 +112,36 @@ char* raw_alloc(size_t size) return mem_alloc; } +void* raw_alloc_by_ownership(TraceTag owner, uintptr_t size) +{ + void* new_mem = raw_alloc(size); + if (!new_mem) { + return NULL; + } + + struct MemUsage* usage = GetSysObject(struct MemUsage, &owner); + if (0 != rbt_insert(&usage->mem_block_map, (uintptr_t)new_mem, NULL)) { + raw_free(new_mem); + return NULL; + } + return new_mem; +} + bool raw_free(char* paddr) { return KBuddyFree(&user_phy_freemem_buddy, paddr); } +bool raw_free_by_ownership(TraceTag owner, void* vaddr) +{ + struct MemUsage* usage = GetSysObject(struct MemUsage, &owner); + RbtNode* node = rbt_search(&usage->mem_block_map, (uintptr_t)vaddr); + assert(NULL != node); + assert(0 == rbt_delete(&usage->mem_block_map, node->key)); + + return raw_free(vaddr); +} + void show_phymem_info() { KFreePagesInfo(&user_phy_freemem_buddy); diff --git a/Ubiquitous/XiZi_AIoT/softkernel/memory/object_allocator.c b/Ubiquitous/XiZi_AIoT/softkernel/memory/object_allocator.c index b79e52ac6..6bc4ea021 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/memory/object_allocator.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/memory/object_allocator.c @@ -32,6 +32,7 @@ Modification: #include "assert.h" #include "kalloc.h" #include "object_allocator.h" +#include "pagetable.h" #define BITMAP_BITS_EMPTY_FULL ((uint64_t)0) #define BITMAP_FIRST_BIT ((uint64_t)1) @@ -47,7 +48,7 @@ Modification: #define ARENA_SIZE_PER_INCREASE PAGE_SIZE #define MAX_NR_ELEMENT_PER_SLABPAGE 64 -void slab_init(struct slab_allocator* const allocator, const size_t element_size) +void slab_init(struct slab_allocator* const allocator, const size_t element_size, char* name) { if (allocator == NULL) { panic("init a NULL slab_allocator\n"); @@ -63,8 +64,11 @@ void slab_init(struct slab_allocator* const allocator, const size_t element_size allocator->nr_elements = allocator->nr_elements > MAX_NR_ELEMENT_PER_SLABPAGE ? MAX_NR_ELEMENT_PER_SLABPAGE : allocator->nr_elements; allocator->bitmap_empty = ~BITMAP_BITS_EMPTY_FULL >> (MAX_NR_ELEMENT_PER_SLABPAGE - allocator->nr_elements); - allocator->partial = allocator->empty = allocator->full = NULL; + + if (name) { + allocator->name = name; + } } void* slab_alloc(struct slab_allocator* const allocator) @@ -107,7 +111,7 @@ void* slab_alloc(struct slab_allocator* const allocator) /* achieve slab from outer arena */ allocator->partial = (struct slab_state*)LOWLEVEL_ALLOC(allocator->slabsize); if (UNLIKELY(allocator->partial == NULL)) { - ERROR("no enough memory\n"); + ERROR("slab %s: no enough memory\n", allocator->name); return allocator->partial = NULL; } allocator->partial->prev = allocator->partial->next = NULL; diff --git a/Ubiquitous/XiZi_AIoT/softkernel/memory/pagetable.c b/Ubiquitous/XiZi_AIoT/softkernel/memory/pagetable.c index 53404786f..b90169857 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/memory/pagetable.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/memory/pagetable.c @@ -143,6 +143,20 @@ static bool _map_user_pages(struct MemSpace* pmemspace, uintptr_t vaddr, uintptr return _map_pages(pmemspace->pgdir.pd_addr, vaddr, paddr, (intptr_t)len, mem_attr); } +bool _map_customizable_page(struct MemSpace* pmemspace, uintptr_t vaddr, uintptr_t paddr, int len, uintptr_t attr) +{ + if (len < 0) { + return false; + } + + if (UNLIKELY(vaddr >= USER_MEM_TOP)) { + ERROR("mapping kernel space.\n"); + return false; + } + + return _map_pages(pmemspace->pgdir.pd_addr, vaddr, paddr, (intptr_t)len, attr); +} + /// assume that a user pagedir is allocated from [0, size) /// if new_size > old_size, allocate more space, /// if old_size > new_size, free extra space, to avoid unnecessary alloc/free. @@ -160,7 +174,8 @@ static uintptr_t _resize_user_pgdir(struct MemSpace* pmemspace, uintptr_t old_si uintptr_t cur_size = ALIGNUP(old_size, PAGE_SIZE); uintptr_t size_needed = ALIGNUP(new_size, PAGE_SIZE) - cur_size; - char* new_page = kalloc(size_needed); + // char* new_page = kalloc(size_needed); + char* new_page = kalloc_by_ownership(pmemspace->kernspace_mem_usage.tag, size_needed); if (new_page == NULL) { ERROR("No memory\n"); return cur_size; @@ -169,7 +184,6 @@ static uintptr_t _resize_user_pgdir(struct MemSpace* pmemspace, uintptr_t old_si if (!xizi_pager.map_pages(pmemspace, cur_size, V2P(new_page), size_needed, false)) { return cur_size; } - CreateResourceTag(NULL, &pmemspace->tag, NULL, TRACER_MEM_FROM_BUDDY_AC_RESOURCE, V2P_WO(new_page)); return new_size; } @@ -251,7 +265,7 @@ struct TopLevelPageDirectory kern_pgdir; void load_kern_pgdir(struct TraceTag* mmu_driver_tag, struct TraceTag* intr_driver_tag) { - if (mmu_driver_tag->meta == NULL) { + if (mmu_driver_tag->inner_node == NULL) { ERROR("Invalid mmu driver tag.\n"); return; } diff --git a/Ubiquitous/XiZi_AIoT/softkernel/memory/share_page.c b/Ubiquitous/XiZi_AIoT/softkernel/memory/share_page.c index a728cfb3f..095d7ddfc 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/memory/share_page.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/memory/share_page.c @@ -44,7 +44,7 @@ static struct slab_allocator* SessionAllocator() static bool init = false; static struct slab_allocator session_slab; if (!init) { - slab_init(&session_slab, sizeof(struct session_backend)); + slab_init(&session_slab, sizeof(struct session_backend), "SessionAllocator"); } return &session_slab; } @@ -204,14 +204,37 @@ void unmap_task_share_pages(struct Thread* task, const uintptr_t task_vaddr, con } } -static int next_session_id = 1; +static int next_session_id = INVALID_SESS_ID + 1; struct session_backend* create_share_pages(struct Thread* client, struct Thread* server, const int capacity) { + /* alloc session backend */ struct session_backend* session_backend = (struct session_backend*)slab_alloc(SessionAllocator()); if (UNLIKELY(session_backend == NULL)) { return NULL; } + session_backend->session_id = next_session_id++; + + if (0 != rbt_insert(&client->cli_sess_map, session_backend->session_id, &session_backend->client_side)) { + DEBUG("Rbt of %s no memory\n", client->name); + slab_free(SessionAllocator(), session_backend); + return NULL; + } + + if (0 != rbt_insert(&server->svr_sess_map, session_backend->session_id, &session_backend->server_side)) { + DEBUG("Rbt of %s no memory\n", server->name); + rbt_delete(&client->cli_sess_map, session_backend->session_id); + slab_free(SessionAllocator(), session_backend); + return NULL; + } + + sem_id_t new_sem_id = ksemaphore_alloc(&xizi_task_manager.semaphore_pool, 0); + if (new_sem_id == INVALID_SEM_ID) { + ERROR("No memory to alloc sem\n"); + slab_free(SessionAllocator(), session_backend); + return NULL; + } + session_backend->client_sem_to_wait = new_sem_id; int true_capacity = ALIGNUP(capacity, PAGE_SIZE); int nr_pages = true_capacity / PAGE_SIZE; @@ -220,6 +243,7 @@ struct session_backend* create_share_pages(struct Thread* client, struct Thread* if (UNLIKELY(kern_vaddr == (uintptr_t)NULL)) { ERROR("No memory for session\n"); slab_free(SessionAllocator(), session_backend); + ksemaphore_free(&xizi_task_manager.semaphore_pool, new_sem_id); return NULL; } @@ -229,6 +253,7 @@ struct session_backend* create_share_pages(struct Thread* client, struct Thread* if (UNLIKELY(client_vaddr == (uintptr_t)NULL)) { kfree((char*)kern_vaddr); slab_free(SessionAllocator(), session_backend); + ksemaphore_free(&xizi_task_manager.semaphore_pool, new_sem_id); return NULL; } @@ -238,11 +263,11 @@ struct session_backend* create_share_pages(struct Thread* client, struct Thread* unmap_task_share_pages(client, client_vaddr, nr_pages); kfree((char*)kern_vaddr); slab_free(SessionAllocator(), session_backend); + ksemaphore_free(&xizi_task_manager.semaphore_pool, new_sem_id); return NULL; } /* build session_backend */ - session_backend->session_id = next_session_id++; session_backend->buf_kernel_addr = kern_vaddr; session_backend->nr_pages = nr_pages; session_backend->client = client; @@ -286,24 +311,40 @@ int delete_share_pages(struct session_backend* session_backend) // close ssesion in server's perspective if (session_backend->server_side.closed && session_backend->server != NULL) { xizi_share_page_manager.unmap_task_share_pages(session_backend->server, session_backend->server_side.buf_addr, session_backend->nr_pages); - doubleListDel(&session_backend->server_side.node); - session_backend->server->memspace->mem_size -= session_backend->nr_pages * PAGE_SIZE; - session_backend->server = NULL; + + ERROR_FREE + { + assert(0 == rbt_delete(&session_backend->server->svr_sess_map, session_backend->session_id)); + doubleListDel(&session_backend->server_side.node); + session_backend->server->memspace->mem_size -= session_backend->nr_pages * PAGE_SIZE; + session_backend->server = NULL; + } } // close ssesion in client's perspective if (session_backend->client_side.closed && session_backend->client != NULL) { xizi_share_page_manager.unmap_task_share_pages(session_backend->client, session_backend->client_side.buf_addr, session_backend->nr_pages); - doubleListDel(&session_backend->client_side.node); - session_backend->client->memspace->mem_size -= session_backend->nr_pages * PAGE_SIZE; - session_backend->client = NULL; + + ERROR_FREE + { + assert(0 == rbt_delete(&session_backend->client->cli_sess_map, session_backend->session_id)); + doubleListDel(&session_backend->client_side.node); + session_backend->client->memspace->mem_size -= session_backend->nr_pages * PAGE_SIZE; + session_backend->client = NULL; + } + + extern bool ksemaphore_free_safe(struct XiziSemaphorePool * sem_pool, sem_id_t sem_id, struct Thread * target); + assert(ksemaphore_free_safe(&xizi_task_manager.semaphore_pool, session_backend->client_sem_to_wait, session_backend->client)); } /* free seesion backend */ if (session_backend->server_side.closed && session_backend->client_side.closed) { - assert(session_backend->client == NULL && session_backend->server == NULL); - kfree((void*)session_backend->buf_kernel_addr); - slab_free(SessionAllocator(), (void*)session_backend); + ERROR_FREE + { + assert(session_backend->client == NULL && session_backend->server == NULL); + assert(kfree((void*)session_backend->buf_kernel_addr)); + slab_free(SessionAllocator(), (void*)session_backend); + } } return 0; @@ -321,4 +362,28 @@ int module_share_page_init(struct SharePageRightGroup* _right_group) /* assign rights to share page module */ right_group = *_right_group; return 0; +} + +void client_close_session(struct Thread* thd, struct client_session* cli_sess) +{ + assert(cli_sess != NULL); + struct session_backend* sess_backend = CLIENT_SESSION_BACKEND(cli_sess); + assert(sess_backend->client == thd); + assert(cli_sess->closed == false); + uintptr_t sess_id = sess_backend->session_id; + cli_sess->closed = true; + xizi_share_page_manager.delete_share_pages(sess_backend); + assert(NULL == rbt_search(&thd->cli_sess_map, sess_id)); +} + +void server_close_session(struct Thread* thd, struct server_session* svr_sess) +{ + assert(svr_sess != NULL); + struct session_backend* sess_backend = SERVER_SESSION_BACKEND(svr_sess); + assert(sess_backend->server == thd); + assert(svr_sess->closed == false); + uintptr_t sess_id = sess_backend->session_id; + svr_sess->closed = true; + xizi_share_page_manager.delete_share_pages(sess_backend); + assert(NULL == rbt_search(&thd->svr_sess_map, sess_id)); } \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/softkernel/syscall/Makefile b/Ubiquitous/XiZi_AIoT/softkernel/syscall/Makefile index 6a144502d..d85d1e220 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/syscall/Makefile +++ b/Ubiquitous/XiZi_AIoT/softkernel/syscall/Makefile @@ -12,6 +12,7 @@ SRC_FILES := syscall.c \ sys_state.c \ sys_mmap.c \ sys_kill.c \ - sys_semaphore.c + sys_semaphore.c \ + sys_wait_session.c include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_close_session.c b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_close_session.c index 24f7ea996..4ba31a83e 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_close_session.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_close_session.c @@ -46,35 +46,50 @@ int sys_close_session(struct Thread* cur_task, struct Session* session) return -1; } - /* check if session is a client one or a server one */ struct session_backend* session_backend = NULL; - struct client_session* client_session = NULL; - DOUBLE_LIST_FOR_EACH_ENTRY(client_session, &cur_task->cli_sess_listhead, node) - { - if ((uintptr_t)session->buf == client_session->buf_addr) { - session_backend = CLIENT_SESSION_BACKEND(client_session); - assert(session_backend->client == cur_task); - assert(client_session->closed == false); - client_session->closed = true; - xizi_share_page_manager.delete_share_pages(session_backend); - break; + /* check if session is a client one or a server one */ + RbtNode* client_session_node = rbt_search(&cur_task->cli_sess_map, session->id); + if (client_session_node != NULL) { + struct client_session* client_session = (struct client_session*)client_session_node->data; + if (CLIENT_SESSION_BACKEND(client_session)->session_id != session->id || // + client_session->buf_addr != (uintptr_t)session->buf) { + ERROR("Error closing session from %s: Invalid session\n", cur_task->name); + return -1; + } + + /* close client session */ + session_backend = CLIENT_SESSION_BACKEND(client_session); + assert(session_backend->client == cur_task); + assert(client_session->closed == false); + client_session->closed = true; + xizi_share_page_manager.delete_share_pages(session_backend); + + struct Thread* server_to_info = session_backend->server; + if (!enqueue(&server_to_info->sessions_to_be_handle, 0, (void*)&session_backend->server_side)) { + // @todo fix memory leak + } else { + assert(!queue_is_empty(&server_to_info->sessions_to_be_handle)); + if (server_to_info->state == BLOCKED) { + xizi_task_manager.task_unblock(session_backend->server); + } } } - if (UNLIKELY(session_backend == NULL)) { - struct server_session* server_session = NULL; - DOUBLE_LIST_FOR_EACH_ENTRY(server_session, &cur_task->svr_sess_listhead, node) - { - if ((uintptr_t)session->buf == server_session->buf_addr) { - session_backend = SERVER_SESSION_BACKEND(server_session); - assert(session_backend->server == cur_task); - assert(server_session->closed == false); - server_session->closed = true; - xizi_share_page_manager.delete_share_pages(session_backend); - break; - } + RbtNode* server_session_node = rbt_search(&cur_task->svr_sess_map, session->id); + if (server_session_node != NULL) { + struct server_session* server_session = (struct server_session*)server_session_node->data; + if (SERVER_SESSION_BACKEND(server_session)->session_id != session->id || // + server_session->buf_addr != (uintptr_t)session->buf) { + ERROR("Error closing session from %s: Invalid session\n", cur_task->name); + return -1; } + + session_backend = SERVER_SESSION_BACKEND(server_session); + assert(session_backend->server == cur_task); + assert(server_session->closed == false); + server_session->closed = true; + xizi_share_page_manager.delete_share_pages(session_backend); } /* close this session */ diff --git a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_connect_session.c b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_connect_session.c index 04922cc11..31cfa08cb 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_connect_session.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_connect_session.c @@ -69,7 +69,7 @@ int sys_connect_session(char* path, int capacity, struct Session* user_session) if (!AchieveResourceTag(&server_identifier_owner, RequireRootTag(), "softkernel/server-identifier")) { panic("Server identifier not initialized.\b"); } - assert(server_identifier_owner.meta != NULL); + assert(server_identifier_owner.inner_node != NULL); struct TraceTag server_tag; if (!AchieveResourceTag(&server_tag, &server_identifier_owner, path)) { diff --git a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_exit.c b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_exit.c index af053b420..929046eea 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_exit.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_exit.c @@ -42,7 +42,8 @@ int sys_exit(struct Thread* ptask) ptask->dead = true; // free that task straightly if it's a blocked task if (ptask->state == BLOCKED) { - xizi_task_manager.free_pcb(ptask); + struct TaskLifecycleOperations* tlo = GetSysObject(struct TaskLifecycleOperations, &xizi_task_manager.task_lifecycle_ops_tag); + tlo->free_thread(ptask); } // yield current task in case it wants to exit itself xizi_task_manager.task_yield_noschedule(cur_cpu()->task, false); diff --git a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_mmap.c b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_mmap.c index becf0b9d7..e0802adcb 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_mmap.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_mmap.c @@ -54,19 +54,135 @@ int sys_mmap(uintptr_t* vaddr, uintptr_t* paddr, int len, int is_dev) } } else { uintptr_t load_vaddr = *vaddr; - char* new_paddr = raw_alloc(true_len); + char* new_paddr = raw_alloc_by_ownership(cur_task->memspace->userspace_mem_usage.tag, true_len); if (new_paddr == NULL) { return -1; } if (xizi_share_page_manager.task_map_pages(cur_task, load_vaddr, (uintptr_t)new_paddr, true_len / PAGE_SIZE, false) == (uintptr_t)NULL) { - raw_free(new_paddr); + raw_free_by_ownership(cur_task->memspace->userspace_mem_usage.tag, new_paddr); return -1; } - CreateResourceTag(NULL, &cur_task->memspace->tag, NULL, TRACER_MEM_FROM_BUDDY_AC_RESOURCE, new_paddr); + CreateResourceTag(NULL, &cur_task->memspace->tag, "USER_MEMORY", TRACER_MEM_SIGNATURE, new_paddr); *paddr = (uintptr_t)new_paddr; } cur_task->memspace->mem_size += true_len; *vaddr = *vaddr + true_len; return 0; +} + +extern bool _map_customizable_page(struct MemSpace* pmemspace, uintptr_t vaddr, uintptr_t paddr, int len, uintptr_t attr); +int sys_mmap_v2(uintptr_t* vaddr, uintptr_t* paddr, int len, sys_mmap_info* info) +{ + struct Thread* cur_task = cur_cpu()->task; + assert(cur_task != NULL); + + if (vaddr == NULL || paddr == NULL) { + ERROR("Invalid vaddr and paddr param from %s\n", cur_task->name); + return -1; + } + + int true_len = ALIGNUP(len, PAGE_SIZE); + + sys_mmap_type type = info->type; + uintptr_t vaddr_to_map = *vaddr; + if (type == SYS_MMAP_CUSTOMIZE) { + if (*paddr != (uintptr_t)NULL) { + if (*paddr == (uintptr_t)NULL || vaddr_to_map == (uintptr_t)NULL) { + ERROR("Customized mapping from %s must have vaddr(%p) and paddr(%p)\n", cur_task->name, vaddr, paddr); + return -1; + } + uintptr_t paddr_to_map = *paddr; + + TraceTag mem_signature_tag; + if (!CreateResourceTag(&mem_signature_tag, &cur_task->memspace->tag, "CUSTOMIZED_MEMORY", TRACER_MEM_SIGNATURE, (void*)vaddr)) { + ERROR("Sign memory signature failed from %s\n", cur_task->name); + return -1; + } + + if (!_map_customizable_page(cur_task->memspace, vaddr_to_map, paddr_to_map, len, info->attr)) { + ERROR("%s mapping page failed(Short of memory)\n", cur_task->name); + DeleteResource(&mem_signature_tag, &cur_task->memspace->tag); + return -1; + } + } else { + char* new_paddr = raw_alloc_by_ownership(cur_task->memspace->userspace_mem_usage.tag, true_len); + if (new_paddr == NULL) { + ERROR("Alloc dynamic memory failed\n"); + return -1; + } + + TraceTag mem_signature_tag; + if (!CreateResourceTag(&mem_signature_tag, &cur_task->memspace->tag, "USER_MEMORY", TRACER_MEM_SIGNATURE, new_paddr)) { + raw_free_by_ownership(cur_task->memspace->userspace_mem_usage.tag, new_paddr); + ERROR("Sign memory signature failed from %s\n", cur_task->name); + return -1; + } + + if (_map_customizable_page(cur_task->memspace, vaddr_to_map, (uintptr_t)new_paddr, len, info->attr) == (uintptr_t)NULL) { + raw_free_by_ownership(cur_task->memspace->userspace_mem_usage.tag, new_paddr); + DeleteResource(&mem_signature_tag, &cur_task->memspace->tag); + return -1; + } + + // assign new_paddr back to user + *paddr = (uintptr_t)new_paddr; + } + + cur_task->memspace->mem_size += true_len; + *vaddr = *vaddr + true_len; + return 0; + } + + if (type == SYS_MMAP_NORMAL) { + bool is_dev = info->is_dev; + + if (*paddr != (uintptr_t)NULL) { + + if (paddr == NULL || *paddr == (uintptr_t)NULL || vaddr_to_map == (uintptr_t)NULL) { + ERROR("Invalid mapping from %s\n", cur_task->name); + return -1; + } + + uintptr_t paddr_to_map = *paddr; + if (paddr_to_map >= PHY_MEM_BASE && paddr_to_map < PHY_MEM_STOP && cur_task->tid > 1) { + ERROR("mapping invalid memory: 0x%p\n", paddr_to_map); + return -1; + } + + if (xizi_share_page_manager.task_map_pages(cur_task, vaddr_to_map, paddr_to_map, true_len / PAGE_SIZE, is_dev) == (uintptr_t)NULL) { + ERROR("%s mapping page failed(Short of memory)\n", cur_task->name); + return -1; + } + + } else { + char* new_paddr = raw_alloc_by_ownership(cur_task->memspace->userspace_mem_usage.tag, true_len); + if (new_paddr == NULL) { + ERROR("Alloc dynamic memory failed\n"); + return -1; + } + + TraceTag mem_signature_tag; + if (!CreateResourceTag(&mem_signature_tag, &cur_task->memspace->tag, "USER_MEMORY", TRACER_MEM_SIGNATURE, new_paddr)) { + raw_free_by_ownership(cur_task->memspace->userspace_mem_usage.tag, new_paddr); + ERROR("Sign memory signature failed from %s\n", cur_task->name); + return -1; + } + + if (xizi_share_page_manager.task_map_pages(cur_task, vaddr_to_map, (uintptr_t)new_paddr, true_len / PAGE_SIZE, false) == (uintptr_t)NULL) { + raw_free_by_ownership(cur_task->memspace->userspace_mem_usage.tag, new_paddr); + DeleteResource(&mem_signature_tag, &cur_task->memspace->tag); + return -1; + } + + // assign new_paddr back to user + *paddr = (uintptr_t)new_paddr; + } + + cur_task->memspace->mem_size += true_len; + *vaddr = *vaddr + true_len; + return 0; + } + + return -1; } \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_poll_session.c b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_poll_session.c index 55451238e..8f2f14e3f 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_poll_session.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_poll_session.c @@ -34,14 +34,7 @@ Modification: #include "syscall.h" #include "task.h" -#define IPCSESSION_MSG(session) ((struct IpcMsg*)((char*)((session)->buf) + (session)->head)) - -static inline bool is_msg_needed(struct IpcMsg* msg) -{ - assert(msg != NULL); - return msg->header.magic == IPC_MSG_MAGIC && msg->header.valid == 1 && msg->header.done == 0 && msg->header.handling == 0; -} - +extern bool ksemaphore_wait(struct XiziSemaphorePool* sem_pool, struct Thread* thd, sem_id_t sem_id); int sys_poll_session(struct Session* userland_session_arr, int arr_capacity) { struct Thread* cur_task = cur_cpu()->task; @@ -50,46 +43,40 @@ int sys_poll_session(struct Session* userland_session_arr, int arr_capacity) return -1; } - struct double_list_node* cur_node = NULL; - struct server_session* server_session = NULL; - /* update old sessions */ - for (int i = 0; i < arr_capacity; i++) { - if (UNLIKELY(userland_session_arr[i].buf == NULL)) { - break; + int cur_userland_idx = 0; + while (!queue_is_empty(&cur_task->sessions_in_handle)) { + struct server_session* server_session = (struct server_session*)queue_front(&cur_task->sessions_in_handle)->data; + assert(server_session != NULL); + + // wrong session info + if (userland_session_arr[cur_userland_idx].id != SERVER_SESSION_BACKEND(server_session)->session_id || // + (uintptr_t)userland_session_arr[cur_userland_idx].buf != server_session->buf_addr) { + ERROR("mismatched old session from %s, user buf: %x, server buf: %x\n", cur_task->name, userland_session_arr[cur_userland_idx].buf, server_session->buf_addr); + } else { + // update session_backend + ksemaphore_signal(&xizi_task_manager.semaphore_pool, SERVER_SESSION_BACKEND(server_session)->client_sem_to_wait); + + server_session->head = userland_session_arr[cur_userland_idx].head; + server_session->tail = userland_session_arr[cur_userland_idx].tail; + userland_session_arr[cur_userland_idx].buf = NULL; + userland_session_arr[cur_userland_idx].id = -1; } - cur_node = cur_task->svr_sess_listhead.next; - server_session = CONTAINER_OF(cur_node, struct server_session, node); - if (UNLIKELY(server_session->buf_addr != (uintptr_t)userland_session_arr[i].buf)) { - ERROR("mismatched old session addr, user buf: %x, server buf: %x\n", userland_session_arr[i].buf, server_session->buf_addr); - return -1; - } - // update session_backend - // if current session is handled - if (server_session->head != userland_session_arr[i].head) { - struct Thread* client = SERVER_SESSION_BACKEND(server_session)->client; - if (client->state == BLOCKED) { - xizi_task_manager.task_unblock(client); - } else { - client->advance_unblock = true; - } - } - server_session->head = userland_session_arr[i].head; - server_session->tail = userland_session_arr[i].tail; - doubleListDel(cur_node); - doubleListAddOnBack(cur_node, &cur_task->svr_sess_listhead); + + assert(dequeue(&cur_task->sessions_in_handle)); + cur_userland_idx++; } /* poll with new sessions */ - int nr_sessions_need_to_handle = 0; - bool has_middle_delete = false; - int session_idx = 0; - DOUBLE_LIST_FOR_EACH_ENTRY(server_session, &cur_task->svr_sess_listhead, node) - { - if (session_idx >= arr_capacity) { + cur_userland_idx = 0; + while (!queue_is_empty(&cur_task->sessions_to_be_handle)) { + if (cur_userland_idx == arr_capacity) { break; } + struct server_session* server_session = (struct server_session*)queue_front(&cur_task->sessions_to_be_handle)->data; + assert(server_session != NULL); + if (SERVER_SESSION_BACKEND(server_session)->client_side.closed) { // client had closed it, then server will close it too struct session_backend* session_backend = SERVER_SESSION_BACKEND(server_session); @@ -98,12 +85,11 @@ int sys_poll_session(struct Session* userland_session_arr, int arr_capacity) assert(server_session->closed == false); server_session->closed = true; xizi_share_page_manager.delete_share_pages(session_backend); - // signal that there is a middle deletion of session - has_middle_delete = true; - break; + dequeue(&cur_task->sessions_to_be_handle); + continue; } - userland_session_arr[session_idx] = (struct Session) { + userland_session_arr[cur_userland_idx] = (struct Session) { .buf = (void*)server_session->buf_addr, .capacity = server_session->capacity, .head = server_session->head, @@ -111,25 +97,24 @@ int sys_poll_session(struct Session* userland_session_arr, int arr_capacity) .id = SERVER_SESSION_BACKEND(server_session)->session_id, }; - struct IpcMsg* msg = IPCSESSION_MSG(&userland_session_arr[session_idx]); - if (msg != NULL && is_msg_needed(msg)) { - nr_sessions_need_to_handle++; + if (!enqueue(&cur_task->sessions_in_handle, 0, (void*)server_session)) { + userland_session_arr[cur_userland_idx].buf = NULL; + userland_session_arr[cur_userland_idx].id = 0; + break; } - - session_idx++; + assert(dequeue(&cur_task->sessions_to_be_handle)); + cur_userland_idx++; } - if (session_idx < arr_capacity) { - userland_session_arr[session_idx].buf = NULL; - if (!has_middle_delete && nr_sessions_need_to_handle == 0) { - if (cur_task->advance_unblock) { - cur_task->advance_unblock = false; - } else { - xizi_task_manager.task_yield_noschedule(cur_task, false); - xizi_task_manager.task_block(&xizi_task_manager.task_blocked_list_head, cur_task); - } - } + // end of userland copy + if (cur_userland_idx < arr_capacity) { + userland_session_arr[cur_userland_idx].buf = NULL; } + if (queue_is_empty(&cur_task->sessions_in_handle) && queue_is_empty(&cur_task->sessions_to_be_handle)) { + xizi_task_manager.task_yield_noschedule(cur_task, false); + // @todo support blocking(now bug at 4 cores running) + // xizi_task_manager.task_block(&xizi_task_manager.task_blocked_list_head, cur_task); + } return 0; } \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_register_as_server.c b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_register_as_server.c index ee0dbce51..f6162742e 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_register_as_server.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_register_as_server.c @@ -35,8 +35,6 @@ Modification: #include "syscall.h" #include "task.h" -#define SERVER_DIR_NAME_SIZE 14 - int sys_register_as_server(char* name) { // get server thread @@ -48,7 +46,7 @@ int sys_register_as_server(char* name) if (!AchieveResourceTag(&server_identifier_set_tag, RequireRootTag(), "softkernel/server-identifier")) { panic("Server identifier not initialized.\b"); } - assert(server_identifier_set_tag.meta != NULL); + assert(server_identifier_set_tag.inner_node != NULL); // create server tag under server tag owner if (!CreateResourceTag(&server->server_identifier, &server_identifier_set_tag, name, TRACER_SERVER_IDENTITY_AC_RESOURCE, server)) { diff --git a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_register_irq.c b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_register_irq.c index 91c3ac6c8..e884160dc 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_register_irq.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_register_irq.c @@ -76,6 +76,12 @@ static void send_irq_to_user(int irq_num) buf->header.magic = IPC_MSG_MAGIC; buf->header.valid = 1; + struct session_backend* session_backend = irq_forward_table[irq_num].p_kernel_session; + struct Thread* server_to_call = session_backend->server; + if (!enqueue(&server_to_call->sessions_to_be_handle, 0, (void*)&session_backend->server_side)) { + return; + } + assert(!queue_is_empty(&server_to_call->sessions_to_be_handle)); if (irq_forward_table[irq_num].handle_task->state == BLOCKED) { xizi_task_manager.task_unblock(irq_forward_table[irq_num].handle_task); } @@ -119,14 +125,15 @@ int sys_register_irq(int irq_num, int irq_opcode) // init kerenl sender proxy if (kernel_irq_proxy == NULL) { /// @todo handle corner cases - struct MemSpace* pmemspace = alloc_memspace(); + struct MemSpace* pmemspace = alloc_memspace("KernelIrqProxy"); if (pmemspace == NULL) { return -1; } xizi_pager.new_pgdir(&pmemspace->pgdir); memcpy(pmemspace->pgdir.pd_addr, kern_pgdir.pd_addr, TOPLEVLE_PAGEDIR_SIZE); - kernel_irq_proxy = xizi_task_manager.new_task_cb(pmemspace); + struct TaskLifecycleOperations* tlo = GetSysObject(struct TaskLifecycleOperations, &xizi_task_manager.task_lifecycle_ops_tag); + kernel_irq_proxy = tlo->new_thread(pmemspace); kernel_irq_proxy->state = NEVER_RUN; } diff --git a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_semaphore.c b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_semaphore.c index 18c0fd7e7..0aff31d7c 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_semaphore.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_semaphore.c @@ -22,7 +22,7 @@ #include "syscall.h" #include "task.h" -extern bool ksemaphore_wait(struct XiziSemaphorePool* sem_pool, struct Thread* thd, uint32_t sem_id); +extern bool ksemaphore_wait(struct XiziSemaphorePool* sem_pool, struct Thread* thd, sem_id_t sem_id); int sys_semaphore(sys_sem_option op, int param) { bool ret = false; diff --git a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_spawn.c b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_spawn.c index fa5994a01..061113b02 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_spawn.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_spawn.c @@ -38,7 +38,7 @@ extern int sys_new_thread(struct MemSpace* pmemspace, struct Thread* task, uintp int sys_spawn(char* img_start, char* name, char** argv) { // alloc a new memspace - struct MemSpace* pmemspace = alloc_memspace(); + struct MemSpace* pmemspace = alloc_memspace(name); if (pmemspace == NULL) { return -1; } @@ -52,10 +52,16 @@ int sys_spawn(char* img_start, char* name, char** argv) } // alloc a new pcb - struct Thread* new_task_cb = xizi_task_manager.new_task_cb(pmemspace); + struct TaskLifecycleOperations* tlo = GetSysObject(struct TaskLifecycleOperations, &xizi_task_manager.task_lifecycle_ops_tag); + struct Thread* new_task_cb = tlo->new_thread(pmemspace); if (UNLIKELY(!new_task_cb)) { - ERROR("Unable to new task control block.\n"); - free_memspace(pmemspace); + ERROR("Unable to new task control block %x.\n"); + // error task allocation may free memspace before hand + // @todo use task ref map to handle this scene + if (NULL != pmemspace->tag.inner_node) { + free_memspace(pmemspace); + } + return -1; } assert(!IS_DOUBLE_LIST_EMPTY(&pmemspace->thread_list_guard)); diff --git a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_state.c b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_state.c index 53406e3e2..6f97f1d1c 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_state.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_state.c @@ -30,6 +30,7 @@ Modification: #include #include +#include "actracer.h" #include "assert.h" #include "buddy.h" #include "log.h" @@ -187,6 +188,10 @@ int sys_state(sys_state_option option, sys_state_info* info) hw_current_second(&info->current_second); break; } + case SYS_STATE_SHOW_ACTREE: { + debug_list_tracetree(); + break; + } case SYS_STATE_TEST: default: break; diff --git a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_thread.c b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_thread.c index f98ed1c81..edd8b0846 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_thread.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_thread.c @@ -40,8 +40,9 @@ int sys_new_thread(struct MemSpace* pmemspace, struct Thread* task, uintptr_t en struct ThreadStackPointer loaded_sp = load_user_stack(pmemspace, argv); if (loaded_sp.stack_idx == -1) { ERROR("Uable to load params to memspace.\n"); - /* memspace is freed alone with free_pcb() */ - xizi_task_manager.free_pcb(task); + /* memspace is freed alone with free_thread() */ + struct TaskLifecycleOperations* tlo = GetSysObject(struct TaskLifecycleOperations, &xizi_task_manager.task_lifecycle_ops_tag); + tlo->free_thread(task); return -1; } @@ -60,7 +61,7 @@ int sys_new_thread(struct MemSpace* pmemspace, struct Thread* task, uintptr_t en last = name + 1; } } - strncpy(task->name, last, sizeof(task->name)); + strncpy(task->name, last, sizeof(task->name) - 1); // init pcb schedule attributes xizi_task_manager.task_set_default_schedule_attr(task); @@ -80,7 +81,8 @@ int sys_thread(uintptr_t entry, char* name, char** argv) // use current task's memspace struct MemSpace* pmemspace = cur_task->memspace; - struct Thread* task = xizi_task_manager.new_task_cb(pmemspace); + struct TaskLifecycleOperations* tlo = GetSysObject(struct TaskLifecycleOperations, &xizi_task_manager.task_lifecycle_ops_tag); + struct Thread* task = tlo->new_thread(pmemspace); if (UNLIKELY(!task)) { ERROR("Unable to new task control block.\n"); return -1; diff --git a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_wait_session.c b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_wait_session.c new file mode 100644 index 000000000..c6b3d00c0 --- /dev/null +++ b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_wait_session.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2020 AIIT XUOS Lab + * XiUOS is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +/** + * @file sys_wait_session.c + * @brief + * @version 3.0 + * @author AIIT XUOS Lab + * @date 2023.08.25 + */ + +/************************************************* +File name: sys_poll_session.c +Description: server poll its connected sessions +Others: +History: +1. Date: 2023-08-28 +Author: AIIT XUOS Lab +Modification: +1. first version +*************************************************/ +#include "multicores.h" +#include "share_page.h" + +#include "syscall.h" + +extern bool ksemaphore_wait(struct XiziSemaphorePool* sem_pool, struct Thread* thd, sem_id_t sem_id); +int sys_wait_session(struct Session* userland_session) +{ + struct Thread* cur_task = cur_cpu()->task; + + RbtNode* client_session_node = rbt_search(&cur_task->cli_sess_map, userland_session->id); + if (client_session_node == NULL) { + ERROR("Error waiting session from %s: Invalid session %d\n", cur_task->name, userland_session->id); + sys_exit(cur_task); + return -1; + } + + struct client_session* client_session = (struct client_session*)client_session_node->data; + if (CLIENT_SESSION_BACKEND(client_session)->session_id != userland_session->id || // + client_session->buf_addr != (uintptr_t)userland_session->buf) { + sys_exit(cur_task); + ERROR("Error waiting session from %s: Invalid session %d\n", cur_task->name, userland_session->id); + return -1; + } + + /* handle calling */ + struct session_backend* session_backend = CLIENT_SESSION_BACKEND(client_session); + struct Thread* server_to_call = session_backend->server; + if (!enqueue(&server_to_call->sessions_to_be_handle, 0, (void*)&session_backend->server_side)) { + sys_exit(cur_task); + return -1; + } + assert(!queue_is_empty(&server_to_call->sessions_to_be_handle)); + + ksemaphore_wait(&xizi_task_manager.semaphore_pool, cur_task, session_backend->client_sem_to_wait); + if (server_to_call->state == BLOCKED) { + xizi_task_manager.task_unblock(session_backend->server); + } + + return 0; +} \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_yield.c b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_yield.c index 45c3f468f..1cc2689a1 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_yield.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_yield.c @@ -37,27 +37,5 @@ int sys_yield(task_yield_reason reason) { struct Thread* cur_task = cur_cpu()->task; xizi_task_manager.task_yield_noschedule(cur_task, false); - - // handle ipc block - if ((reason & SYS_TASK_YIELD_BLOCK_IPC) != 0) { - if (cur_task->advance_unblock) { - cur_task->advance_unblock = false; - return 0; - } else { - xizi_task_manager.task_block(&xizi_task_manager.task_blocked_list_head, cur_task); - } - - // wake up all possible server - struct client_session* client_session = NULL; - DOUBLE_LIST_FOR_EACH_ENTRY(client_session, &cur_task->cli_sess_listhead, node) - { - assert(client_session != NULL); - struct session_backend* session_backend = CLIENT_SESSION_BACKEND(client_session); - if (session_backend->server->state == BLOCKED) { - xizi_task_manager.task_unblock(session_backend->server); - } - } - } - return 0; } \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/softkernel/syscall/syscall.c b/Ubiquitous/XiZi_AIoT/softkernel/syscall/syscall.c index c6985c194..76135f24c 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/syscall/syscall.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/syscall/syscall.c @@ -69,7 +69,7 @@ int syscall(int sys_num, uintptr_t param1, uintptr_t param2, uintptr_t param3, u ret = sys_state(param1, (sys_state_info*)param2); break; case SYSCALL_MMAP: - ret = sys_mmap((uintptr_t*)param1, (uintptr_t*)param2, (int)param3, (int)param4); + ret = sys_mmap_v2((uintptr_t*)param1, (uintptr_t*)param2, (int)param3, (sys_mmap_info*)param4); break; case SYSCALL_REGISTER_IRQ: ret = sys_register_irq((int)param1, (int)param2); @@ -83,6 +83,9 @@ int syscall(int sys_num, uintptr_t param1, uintptr_t param2, uintptr_t param3, u case SYSCALL_SLEEP: ret = sys_sleep((intptr_t)param1); break; + case SYSCALL_WAIT_SESSION: + ret = sys_wait_session((struct Session*)param1); + break; default: ERROR("Unsurport syscall(%d) right now\n", sys_num); ret = -1; diff --git a/Ubiquitous/XiZi_AIoT/softkernel/task/memspace.c b/Ubiquitous/XiZi_AIoT/softkernel/task/memspace.c index 3fce45d05..bfa793730 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/task/memspace.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/task/memspace.c @@ -41,7 +41,7 @@ Modification: #define MAX_SUPPORT_PARAMS 32 -struct MemSpace* alloc_memspace() +struct MemSpace* alloc_memspace(char* name) { struct MemSpace* pmemspace = slab_alloc(&xizi_task_manager.memspace_allocator); if (pmemspace == NULL) { @@ -56,28 +56,51 @@ struct MemSpace* alloc_memspace() pmemspace->mem_size = 0; pmemspace->pgdir.pd_addr = 0; pmemspace->thread_to_notify = NULL; - CreateResourceTag(&pmemspace->tag, &xizi_task_manager.tag, NULL, TRACER_OWNER, (void*)pmemspace); + if (!CreateResourceTag(&pmemspace->tag, &xizi_task_manager.tag, name, TRACER_OWNER, (void*)pmemspace)) { + DEBUG("Register MemSpace %s failed\n", name); + slab_free(&xizi_task_manager.memspace_allocator, (void*)pmemspace); + return NULL; + } + assert(pmemspace->tag.inner_node != NULL); + + if (!CreateResourceTag(&pmemspace->kernspace_mem_usage.tag, &pmemspace->tag, "MemUsage", TRACER_SYSOBJECT, (void*)&pmemspace->kernspace_mem_usage) || // + !CreateResourceTag(&pmemspace->userspace_mem_usage.tag, &pmemspace->tag, "UserMemUsage", TRACER_SYSOBJECT, (void*)&pmemspace->userspace_mem_usage) || // + !CreateResourceTag(&pmemspace->customized_mapping_mem_map.tag, &pmemspace->tag, "CustomizaedMemMapping", TRACER_SYSOBJECT, (void*)&pmemspace->customized_mapping_mem_map)) { + DEBUG("Register MemUsage %s failed\n", name); + slab_free(&xizi_task_manager.memspace_allocator, (void*)pmemspace); + DeleteResource(&pmemspace->tag, &xizi_task_manager.tag); + return NULL; + } + + rbtree_init(&pmemspace->kernspace_mem_usage.mem_block_map); + rbtree_init(&pmemspace->userspace_mem_usage.mem_block_map); + rbtree_init(&pmemspace->customized_mapping_mem_map.mem_block_map); return pmemspace; } void free_memspace(struct MemSpace* pmemspace) { assert(pmemspace != NULL); + assert(IS_DOUBLE_LIST_EMPTY(&pmemspace->thread_list_guard)); /* free page table and all its allocated memories */ if (pmemspace->pgdir.pd_addr != NULL) { xizi_pager.free_user_pgdir(&pmemspace->pgdir); } - TracerNode* tmp_node = NULL; - DOUBLE_LIST_FOR_EACH_ENTRY(tmp_node, &pmemspace->tag.meta->children_guard, list_node) - { - assert((uintptr_t)tmp_node->p_resource >= PHY_MEM_BASE && (uintptr_t)tmp_node->p_resource < PHY_MEM_STOP); - if ((uintptr_t)tmp_node->p_resource < PHY_USER_FREEMEM_BASE) { - kfree(P2V(tmp_node->p_resource)); - } else { - raw_free(tmp_node->p_resource); - } + // delete space + RbtNode* rbt_node = pmemspace->kernspace_mem_usage.mem_block_map.root; + while (rbt_node != NULL) { + assert((uintptr_t)V2P(rbt_node->key) >= PHY_MEM_BASE && (uintptr_t)V2P(rbt_node->key) < PHY_MEM_STOP); + kfree_by_ownership(pmemspace->kernspace_mem_usage.tag, (void*)rbt_node->key); + rbt_node = pmemspace->kernspace_mem_usage.mem_block_map.root; + } + + rbt_node = pmemspace->userspace_mem_usage.mem_block_map.root; + while (rbt_node != NULL) { + assert((uintptr_t)rbt_node->key >= PHY_MEM_BASE && (uintptr_t)rbt_node->key < PHY_MEM_STOP); + raw_free_by_ownership(pmemspace->userspace_mem_usage.tag, (void*)rbt_node->key); + rbt_node = pmemspace->userspace_mem_usage.mem_block_map.root; } /* free ipc virt address allocator */ @@ -213,7 +236,7 @@ struct ThreadStackPointer load_user_stack(struct MemSpace* pmemspace, char** arg } /* allocate memory space for user stack */ - uintptr_t* stack_bottom = (uintptr_t*)kalloc(USER_STACK_SIZE); + uintptr_t* stack_bottom = (uintptr_t*)kalloc_by_ownership(pmemspace->kernspace_mem_usage.tag, USER_STACK_SIZE); if (UNLIKELY(stack_bottom == NULL)) { ERROR("No memory to alloc user stack.\n"); handle_error_stack_loading(pmemspace, stack_idx, stack_bottom, false); diff --git a/Ubiquitous/XiZi_AIoT/softkernel/task/schedule.c b/Ubiquitous/XiZi_AIoT/softkernel/task/schedule.c index 9df773558..ca92119a8 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/task/schedule.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/task/schedule.c @@ -28,7 +28,7 @@ Modification: 1. first version *************************************************/ #include "log.h" -#include "scheduler.h" +#include "schedule_algo.h" struct Thread* max_priority_runnable_task(void) { @@ -47,7 +47,9 @@ struct Thread* max_priority_runnable_task(void) // found a runnable task, stop this look up return task; } else if (task->dead && task->state != RUNNING) { - xizi_task_manager.free_pcb(task); + + struct TaskLifecycleOperations* tlo = GetSysObject(struct TaskLifecycleOperations, &xizi_task_manager.task_lifecycle_ops_tag); + tlo->free_thread(task); return NULL; } } @@ -64,7 +66,8 @@ struct Thread* round_robin_runnable_task(uint32_t priority) // found a runnable task, stop this look up return task; } else if (task->dead && task->state != RUNNING) { - xizi_task_manager.free_pcb(task); + struct TaskLifecycleOperations* tlo = GetSysObject(struct TaskLifecycleOperations, &xizi_task_manager.task_lifecycle_ops_tag); + tlo->free_thread(task); return NULL; } } diff --git a/Ubiquitous/XiZi_AIoT/softkernel/task/semaphore.c b/Ubiquitous/XiZi_AIoT/softkernel/task/semaphore.c index f1c5b5443..c6bbe80ba 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/task/semaphore.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/task/semaphore.c @@ -24,29 +24,28 @@ void semaphore_pool_init(struct XiziSemaphorePool* sem_pool) { assert(sem_pool != NULL); - sem_pool->next_sem_id = 1; - slab_init(&sem_pool->allocator, sizeof(struct ksemaphore)); + sem_pool->next_sem_id = INVALID_SEM_ID + 1; + slab_init(&sem_pool->allocator, sizeof(struct ksemaphore), "SemAllocator"); doubleListNodeInit(&sem_pool->sem_list_guard); + rbtree_init(&sem_pool->sem_pool_map); + sem_pool->nr_sem = 0; } -static inline struct ksemaphore* ksemaphore_get_by_id(struct XiziSemaphorePool* sem_pool, int sem_id) +static inline struct ksemaphore* ksemaphore_get_by_id(struct XiziSemaphorePool* sem_pool, sem_id_t sem_id) { - struct ksemaphore* sem = NULL; - DOUBLE_LIST_FOR_EACH_ENTRY(sem, &sem_pool->sem_list_guard, sem_list_node) - { - if (sem->id == sem_id) { - return sem; - } + RbtNode* target_sem_node = rbt_search(&sem_pool->sem_pool_map, sem_id); + if (target_sem_node == NULL) { + return NULL; } - return NULL; + return (struct ksemaphore*)target_sem_node->data; } -int ksemaphore_alloc(struct XiziSemaphorePool* sem_pool, int val) +sem_id_t ksemaphore_alloc(struct XiziSemaphorePool* sem_pool, sem_val_t val) { struct ksemaphore* sem = (struct ksemaphore*)slab_alloc(&sem_pool->allocator); if (sem == NULL) { ERROR("No memeory to alloc new semaphore.\n"); - return -1; + return INVALID_SEM_ID; } /* No error down here */ @@ -55,19 +54,38 @@ int ksemaphore_alloc(struct XiziSemaphorePool* sem_pool, int val) sem->id = sem_pool->next_sem_id++; if (UNLIKELY(sem->id == 0)) { slab_free(&sem_pool->allocator, sem); - return -1; + return INVALID_SEM_ID; } sem->val = val; doubleListNodeInit(&sem->sem_list_node); doubleListNodeInit(&sem->wait_list_guard); - /* list sem to sem_pool */ + if (0 != rbt_insert(&sem_pool->sem_pool_map, sem->id, sem)) { + slab_free(&sem_pool->allocator, sem); + return INVALID_SEM_ID; + } + doubleListAddOnHead(&sem->sem_list_node, &sem_pool->sem_list_guard); + sem_pool->nr_sem++; return sem->id; } -bool ksemaphore_wait(struct XiziSemaphorePool* sem_pool, struct Thread* thd, uint32_t sem_id) +bool ksemaphore_consume(struct XiziSemaphorePool* sem_pool, sem_id_t sem_id, sem_val_t decre) +{ + struct ksemaphore* sem = ksemaphore_get_by_id(sem_pool, sem_id); + // invalid sem id + if (sem == NULL) { + return false; + } + + // if (decre >= 0) { + sem->val -= decre; + // } + return true; +} + +bool ksemaphore_wait(struct XiziSemaphorePool* sem_pool, struct Thread* thd, sem_id_t sem_id) { assert(thd != NULL); assert(thd->state == RUNNING); @@ -77,6 +95,7 @@ bool ksemaphore_wait(struct XiziSemaphorePool* sem_pool, struct Thread* thd, uin if (sem == NULL) { return false; } + // DEBUG("%s waiting sem %lu(%d), nr_sem: %d I\n", thd->name, sem_id, sem->val, sem_pool->nr_sem); // no need to wait if (sem->val > 0) { @@ -91,7 +110,7 @@ bool ksemaphore_wait(struct XiziSemaphorePool* sem_pool, struct Thread* thd, uin return true; } -bool ksemaphore_signal(struct XiziSemaphorePool* sem_pool, uint32_t sem_id) +bool ksemaphore_signal(struct XiziSemaphorePool* sem_pool, sem_id_t sem_id) { /* find sem */ struct ksemaphore* sem = ksemaphore_get_by_id(sem_pool, sem_id); @@ -112,7 +131,44 @@ bool ksemaphore_signal(struct XiziSemaphorePool* sem_pool, uint32_t sem_id) return true; } -bool ksemaphore_free(struct XiziSemaphorePool* sem_pool, uint32_t sem_id) +bool ksemaphore_signal_no_wake(struct XiziSemaphorePool* sem_pool, sem_id_t sem_id) +{ + /* find sem */ + struct ksemaphore* sem = ksemaphore_get_by_id(sem_pool, sem_id); + // invalid sem id + if (sem == NULL) { + return false; + } + + sem->val++; + return true; +} + +bool ksemaphore_free(struct XiziSemaphorePool* sem_pool, sem_id_t sem_id) +{ + /* find sem */ + struct ksemaphore* sem = ksemaphore_get_by_id(sem_pool, sem_id); + // invalid sem id + if (sem == NULL) { + return false; + } + + struct Thread* thd = NULL; + DOUBLE_LIST_FOR_EACH_ENTRY(thd, &sem->wait_list_guard, node) + { + assert(thd != NULL && thd->state == BLOCKED); + xizi_task_manager.task_unblock(thd); + } + + rbt_delete(&sem_pool->sem_pool_map, sem_id); + doubleListDel(&sem->sem_list_node); + slab_free(&sem_pool->allocator, sem); + sem_pool->nr_sem--; + + return true; +} + +bool ksemaphore_free_safe(struct XiziSemaphorePool* sem_pool, sem_id_t sem_id, struct Thread* target) { /* find sem */ struct ksemaphore* sem = ksemaphore_get_by_id(sem_pool, sem_id); @@ -125,11 +181,15 @@ bool ksemaphore_free(struct XiziSemaphorePool* sem_pool, uint32_t sem_id) DOUBLE_LIST_FOR_EACH_ENTRY(thd, &sem->wait_list_guard, node) { assert(thd != NULL); - xizi_task_manager.task_unblock(thd); + if (target != thd && thd->state == BLOCKED) { + xizi_task_manager.task_unblock(thd); + } } + rbt_delete(&sem_pool->sem_pool_map, sem_id); doubleListDel(&sem->sem_list_node); slab_free(&sem_pool->allocator, sem); + sem_pool->nr_sem--; return true; -} +} \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/softkernel/task/task.c b/Ubiquitous/XiZi_AIoT/softkernel/task/task.c index 9b9a90ede..3bf4fb013 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/task/task.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/task/task.c @@ -35,7 +35,7 @@ Modification: #include "kalloc.h" #include "memspace.h" #include "multicores.h" -#include "scheduler.h" +#include "schedule_algo.h" #include "syscall.h" #include "task.h" #include "trap_common.h" @@ -43,6 +43,9 @@ Modification: struct CPU global_cpus[NR_CPU]; uint32_t ready_task_priority; +struct GlobalTaskPool global_task_pool; +extern struct TaskLifecycleOperations task_lifecycle_ops; + static inline void task_node_leave_list(struct Thread* task) { doubleListDel(&task->node); @@ -65,19 +68,30 @@ static inline void task_node_add_to_ready_list_back(struct Thread* task) static void _task_manager_init() { + assert(CreateResourceTag(&xizi_task_manager.task_lifecycle_ops_tag, &xizi_task_manager.tag, // + "TaskLifeCycleOpTool", TRACER_SYSOBJECT, (void*)&task_lifecycle_ops)); + // init task list to NULL for (int i = 0; i < TASK_MAX_PRIORITY; i++) { doubleListNodeInit(&xizi_task_manager.task_list_head[i]); } + + /* task scheduling list */ doubleListNodeInit(&xizi_task_manager.task_blocked_list_head); doubleListNodeInit(&xizi_task_manager.task_running_list_head); doubleListNodeInit(&xizi_task_manager.task_sleep_list_head); // init task (slab) allocator - slab_init(&xizi_task_manager.memspace_allocator, sizeof(struct MemSpace)); - slab_init(&xizi_task_manager.task_allocator, sizeof(struct Thread)); - slab_init(&xizi_task_manager.task_buddy_allocator, sizeof(struct KBuddy)); + slab_init(&xizi_task_manager.memspace_allocator, sizeof(struct MemSpace), "MemlpaceCtrlBlockAllocator"); + slab_init(&xizi_task_manager.task_allocator, sizeof(struct Thread), "ThreadCtrlBlockAllocator"); + slab_init(&xizi_task_manager.task_buddy_allocator, sizeof(struct KBuddy), "DMBuddyAllocator"); + + /* global semaphore factory */ semaphore_pool_init(&xizi_task_manager.semaphore_pool); + /* task pool */ + doubleListNodeInit(&global_task_pool.thd_listing_head); + rbtree_init(&global_task_pool.thd_ref_map); + // tid pool xizi_task_manager.next_pid = 0; @@ -85,131 +99,6 @@ static void _task_manager_init() ready_task_priority = 0; } -/// @brief alloc a new task without init -static struct Thread* _alloc_task_cb() -{ - // alloc task and add it to used task list - struct Thread* task = (struct Thread*)slab_alloc(&xizi_task_manager.task_allocator); - if (UNLIKELY(task == NULL)) { - ERROR("Not enough memory\n"); - return NULL; - } - // set tid once task is allocated - memset(task, 0, sizeof(*task)); - task->tid = xizi_task_manager.next_pid++; - task->thread_context.user_stack_idx = -1; - - return task; -} - -int _task_return_sys_resources(struct Thread* ptask) -{ - assert(ptask != NULL); - - /* handle sessions for condition 1, ref. delete_share_pages() */ - struct session_backend* session_backend = NULL; - // close all server_sessions - struct server_session* server_session = NULL; - while (!IS_DOUBLE_LIST_EMPTY(&ptask->svr_sess_listhead)) { - server_session = CONTAINER_OF(ptask->svr_sess_listhead.next, struct server_session, node); - assert(server_session != NULL); - session_backend = SERVER_SESSION_BACKEND(server_session); - assert(session_backend->server == ptask); - // cut the connection from task to session - server_session->closed = true; - xizi_share_page_manager.delete_share_pages(session_backend); - } - // close all client_sessions - struct client_session* client_session = NULL; - while (!IS_DOUBLE_LIST_EMPTY(&ptask->cli_sess_listhead)) { - client_session = CONTAINER_OF(ptask->cli_sess_listhead.next, struct client_session, node); - assert(client_session != NULL); - session_backend = CLIENT_SESSION_BACKEND(client_session); - assert(session_backend->client == ptask); - // cut the connection from task to session - client_session->closed = true; - xizi_share_page_manager.delete_share_pages(session_backend); - } - - if (ptask->server_identifier.meta != NULL) { - struct TraceTag server_identifier_owner; - AchieveResourceTag(&server_identifier_owner, RequireRootTag(), "softkernel/server-identifier"); - assert(server_identifier_owner.meta != NULL); - DeleteResource(&ptask->server_identifier, &server_identifier_owner); - } - - // delete registered irq if there is one - if (ptask->bind_irq) { - sys_unbind_irq_all(ptask); - } - - return 0; -} - -/// @brief this function changes task list without locking, so it must be called inside a lock critical area -/// @param task -static void _dealloc_task_cb(struct Thread* task) -{ - if (UNLIKELY(task == NULL)) { - ERROR("deallocating a NULL task\n"); - return; - } - - _task_return_sys_resources(task); - - /* free thread's user stack */ - if (task->thread_context.user_stack_idx != -1) { - // stack is mapped in vspace, so it should be freed from pgdir - assert(task->thread_context.user_stack_idx >= 0 && task->thread_context.user_stack_idx < 64); - assert(task->memspace != NULL); - - /* the stack must have be set in memspace if bitmap has been set */ - assert(xizi_pager.unmap_pages(task->memspace->pgdir.pd_addr, task->thread_context.uspace_stack_addr, USER_STACK_SIZE)); - bitmap64_free(&task->memspace->thread_stack_idx_bitmap, task->thread_context.user_stack_idx); - /* thread's user stack space is also allocated for kernel free space */ - assert(kfree((char*)task->thread_context.ustack_kvaddr)); - - if (task->memspace != NULL) { - task->memspace->mem_size -= USER_STACK_SIZE; - } - } - - /* free thread's kernel stack */ - if (task->thread_context.kern_stack_addr) { - kfree((char*)task->thread_context.kern_stack_addr); - } - - /* free memspace if needed to */ - if (task->memspace != NULL) { - // awake deamon in this memspace - if (task->memspace->thread_to_notify != NULL) { - if (task->memspace->thread_to_notify != task) { - if (task->memspace->thread_to_notify->state == BLOCKED) { - xizi_task_manager.task_unblock(task->memspace->thread_to_notify); - } else { - task->memspace->thread_to_notify->advance_unblock = true; - } - } else if (task->memspace->thread_to_notify == task) { - task->memspace->thread_to_notify = NULL; - } - } - - doubleListDel(&task->memspace_list_node); - /* free memspace if thread is the last one using it */ - if (IS_DOUBLE_LIST_EMPTY(&task->memspace->thread_list_guard)) { - // free memspace - free_memspace(task->memspace); - } - } - - // remove thread from used task list - task_node_leave_list(task); - - // free task back to allocator - slab_free(&xizi_task_manager.task_allocator, (void*)task); -} - -/* alloc a new task with init */ extern void trap_return(void); __attribute__((optimize("O0"))) void task_prepare_enter() { @@ -217,59 +106,206 @@ __attribute__((optimize("O0"))) void task_prepare_enter() trap_return(); } -static struct Thread* _new_task_cb(struct MemSpace* pmemspace) +/// @brief this function changes task list without locking, so it must be called inside a lock critical area +/// @param task +static void _free_thread(struct Thread* task) { - // alloc task space - struct Thread* task = _alloc_task_cb(); - if (!task) { - return NULL; + if (UNLIKELY(task == NULL)) { + ERROR("deallocating a NULL task\n"); + return; + } + assert(task->state >= INIT); + assert(task->memspace != NULL); + + // ignore [name, tid, dead, ] + // case thread context [kern_stack_addr, ] + + /* 1. close all ipcall sessions */ + ERROR_FREE + { + /* handle sessions for condition 1, ref. delete_share_pages() */ + // close all server_sessions + while (!IS_DOUBLE_LIST_EMPTY(&task->svr_sess_listhead)) { + // RbtNode* sess_ref_node = ptask->svr_sess_map.root; + struct server_session* svr_session = CONTAINER_OF(task->svr_sess_listhead.next, struct server_session, node); + server_close_session(task, svr_session); + } + + // close all client_sessions + while (!IS_DOUBLE_LIST_EMPTY(&task->cli_sess_listhead)) { + // RbtNode* sess_ref_node = ptask->cli_sess_map.root; + struct client_session* cli_session = CONTAINER_OF(task->cli_sess_listhead.next, struct client_session, node); + client_close_session(task, cli_session); + + // info server that session is closed + struct session_backend* session_backend = CLIENT_SESSION_BACKEND(cli_session); + struct Thread* server_to_info = session_backend->server; + if (!enqueue(&server_to_info->sessions_to_be_handle, 0, (void*)&session_backend->server_side)) { + // @todo fix memory leak + } else { + assert(!queue_is_empty(&server_to_info->sessions_to_be_handle)); + if (server_to_info->state == BLOCKED) { + xizi_task_manager.task_unblock(session_backend->server); + } + } + } + + assert(IS_DOUBLE_LIST_EMPTY(&task->svr_sess_listhead)); + assert(IS_DOUBLE_LIST_EMPTY(&task->cli_sess_listhead)); + // assert(rbt_is_empty(&task->svr_sess_map)); + // assert(rbt_is_empty(&task->cli_sess_map)); + + /// @todo handle server transition + /* delete server identifier */ + if (task->server_identifier.inner_node != NULL) { + // @todo figure out server-identifier ownership + struct TraceTag server_identifier_owner; + AchieveResourceTag(&server_identifier_owner, RequireRootTag(), "softkernel/server-identifier"); + assert(server_identifier_owner.inner_node != NULL); + assert(DeleteResource(&task->server_identifier, &server_identifier_owner)); + } } - /* init basic task member */ - doubleListNodeInit(&task->cli_sess_listhead); - doubleListNodeInit(&task->svr_sess_listhead); - - /* when creating a new task, memspace will be freed outside during memory shortage */ - task->memspace = NULL; - - /* init main thread of task */ - task->thread_context.task = task; - // alloc stack page for task - if ((void*)(task->thread_context.kern_stack_addr = (uintptr_t)kalloc(USER_STACK_SIZE)) == NULL) { - /* here inside, will no free memspace */ - _dealloc_task_cb(task); - return NULL; + /* 2. quit interrupt handling */ + ERROR_FREE + { + // delete registered irq if there is one + if (task->bind_irq) { + sys_unbind_irq_all(task); + } } - /* from now on, _new_task_cb() will not generate error */ - /* init vm */ + /* 3. quit schedule */ + ERROR_FREE + { + // remove thread from used task list + task_node_leave_list(task); + /// ignore [ticks, sleep context, state] + } + + /* 3. free context */ + ERROR_FREE + { + /* free thread's kernel stack */ + assert(task->thread_context.kern_stack_addr != (uintptr_t)NULL); + assert(kfree_by_ownership(task->memspace->kernspace_mem_usage.tag, (void*)task->thread_context.kern_stack_addr)); + + /* free thread's user stack */ + if (task->thread_context.user_stack_idx != -1) { + // stack is mapped in vspace, so it should be freed from pgdir + assert(task->memspace != NULL); + assert(task->thread_context.user_stack_idx >= 0 && task->thread_context.user_stack_idx < 64); + + /* the stack must have be set in memspace if bitmap has been set */ + assert(xizi_pager.unmap_pages(task->memspace->pgdir.pd_addr, task->thread_context.uspace_stack_addr, USER_STACK_SIZE)); + bitmap64_free(&task->memspace->thread_stack_idx_bitmap, task->thread_context.user_stack_idx); + /* thread's user stack space is also allocated for kernel free space */ + assert(kfree_by_ownership(task->memspace->kernspace_mem_usage.tag, (char*)task->thread_context.ustack_kvaddr)); + } + } + + /* free memspace if needed to */ + doubleListDel(&task->memspace_list_node); + /* free memspace if thread is the last one using it */ + if (IS_DOUBLE_LIST_EMPTY(&task->memspace->thread_list_guard)) { + // free memspace + free_memspace(task->memspace); + } else if (task->memspace->thread_to_notify != NULL) { + // awake deamon in this memspace + if (task->memspace->thread_to_notify != task) { + if (task->memspace->thread_to_notify->state == BLOCKED) { + xizi_task_manager.task_unblock(task->memspace->thread_to_notify); + } else { + task->memspace->thread_to_notify->advance_unblock = true; + } + } else if (task->memspace->thread_to_notify == task) { + task->memspace->thread_to_notify = NULL; + } + } + + // free task back to allocator + ERROR_FREE + { + slab_free(&xizi_task_manager.task_allocator, (void*)task); + } +} + +/* alloc a new task with init */ +static struct Thread* _new_thread(struct MemSpace* pmemspace) +{ assert(pmemspace != NULL); - task->memspace = pmemspace; - task->thread_context.user_stack_idx = -1; - doubleListNodeInit(&task->memspace_list_node); - doubleListAddOnBack(&task->memspace_list_node, &pmemspace->thread_list_guard); - /* set context of main thread stack */ - /// stack bottom - memset((void*)task->thread_context.kern_stack_addr, 0x00, USER_STACK_SIZE); - char* sp = (char*)task->thread_context.kern_stack_addr + USER_STACK_SIZE - 4; + // alloc task space + struct Thread* task = (struct Thread*)slab_alloc(&xizi_task_manager.task_allocator); + if (task == NULL) { + ERROR("Not enough memory\n"); + return NULL; + } - /// 1. trap frame into stack, for process to nomally return by trap_return - sp -= sizeof(*task->thread_context.trapframe); - task->thread_context.trapframe = (struct trapframe*)sp; + // alloc stack page for task + if ((void*)(task->thread_context.kern_stack_addr = (uintptr_t)kalloc_by_ownership(pmemspace->kernspace_mem_usage.tag, USER_STACK_SIZE)) == NULL) { + /* here inside, will no free memspace */ + slab_free(&xizi_task_manager.task_allocator, (void*)task); + return NULL; + } - /// 2. context into stack - sp -= sizeof(*task->thread_context.context); - task->thread_context.context = (struct context*)sp; - arch_init_context(task->thread_context.context); + ERROR_FREE + { + /* init basic task ref member */ + task->tid = xizi_task_manager.next_pid++; + task->bind_irq = false; + /* vm & memory member */ + task->thread_context.user_stack_idx = -1; + task->memspace = pmemspace; + doubleListNodeInit(&task->memspace_list_node); + doubleListAddOnBack(&task->memspace_list_node, &pmemspace->thread_list_guard); + + /* thread context */ + task->thread_context.task = task; + memset((void*)task->thread_context.kern_stack_addr, 0x00, USER_STACK_SIZE); + /// stack bottom + char* sp = (char*)task->thread_context.kern_stack_addr + USER_STACK_SIZE - 4; + + /// 1. trap frame into stack, for process to nomally return by trap_return + /// trapframe (user context) + sp -= sizeof(*task->thread_context.trapframe); + task->thread_context.trapframe = (struct trapframe*)sp; + + /// 2. context into stack + // (kernel context) + sp -= sizeof(*task->thread_context.context); + task->thread_context.context = (struct context*)sp; + arch_init_context(task->thread_context.context); + + /* ipc member */ + doubleListNodeInit(&task->cli_sess_listhead); + doubleListNodeInit(&task->svr_sess_listhead); + rbtree_init(&task->cli_sess_map); + rbtree_init(&task->svr_sess_map); + queue_init(&task->sessions_in_handle); + queue_init(&task->sessions_to_be_handle); + /// server identifier + task->server_identifier.inner_node = NULL; + } + + // [name] + // [schedule related] + + task->state = INIT; return task; } +struct TaskLifecycleOperations task_lifecycle_ops = { + .new_thread = _new_thread, + .free_thread = _free_thread, +}; + static void _task_set_default_schedule_attr(struct Thread* task) { task->remain_tick = TASK_CLOCK_TICK; task->maxium_tick = TASK_CLOCK_TICK * 10; + task->dead = false; task->state = READY; task->priority = TASK_DEFAULT_PRIORITY; task_node_add_to_ready_list_head(task); @@ -288,7 +324,7 @@ extern void context_switch(struct context**, struct context*); static void _scheduler(struct SchedulerRightGroup right_group) { struct MmuCommonDone* p_mmu_driver = AchieveResource(&right_group.mmu_driver_tag); -// struct XiziTrapDriver* p_intr_driver = AchieveResource(&right_group.intr_driver_tag); + // struct XiziTrapDriver* p_intr_driver = AchieveResource(&right_group.intr_driver_tag); struct Thread* next_task; struct CPU* cpu = cur_cpu(); @@ -379,8 +415,6 @@ static void _set_cur_task_priority(int priority) struct XiziTaskManager xizi_task_manager = { .init = _task_manager_init, - .new_task_cb = _new_task_cb, - .free_pcb = _dealloc_task_cb, .task_set_default_schedule_attr = _task_set_default_schedule_attr, .next_runnable_task = max_priority_runnable_task, diff --git a/Ubiquitous/XiZi_AIoT/softkernel/tools/Makefile b/Ubiquitous/XiZi_AIoT/softkernel/tools/Makefile new file mode 100644 index 000000000..a6e840e59 --- /dev/null +++ b/Ubiquitous/XiZi_AIoT/softkernel/tools/Makefile @@ -0,0 +1,4 @@ + +SRC_FILES := queue.c rbtree.c + +include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiZi_AIoT/softkernel/tools/queue.c b/Ubiquitous/XiZi_AIoT/softkernel/tools/queue.c new file mode 100644 index 000000000..54af4b41d --- /dev/null +++ b/Ubiquitous/XiZi_AIoT/softkernel/tools/queue.c @@ -0,0 +1,79 @@ + + +#include "actracer.h" +#include "assert.h" + +#include "queue.h" + +struct QueueFactory { + TraceTag tag; + struct slab_allocator queue_ele_allocator; +}; +static struct QueueFactory queue_factory; + +void module_queue_factory_init(TraceTag* _softkernel_tag) +{ + CreateResourceTag(&queue_factory.tag, _softkernel_tag, "GlobalQueueFactory", TRACER_SYSOBJECT, &queue_factory); + slab_init(&queue_factory.queue_ele_allocator, sizeof(struct QueueNode), "QueueNodeAllocator"); +} + +void queue_init(Queue* queue) +{ + queue->front = NULL; + queue->rear = NULL; + queue->nr_ele = 0; +} + +struct QueueNode* queue_front(Queue* queue) +{ + return queue->front; +} + +bool queue_is_empty(Queue* queue) +{ + if (queue->front == NULL) { + assert(queue->nr_ele == 0); + return true; + } + + return false; +} + +bool dequeue(Queue* queue) +{ + struct QueueNode* temp = queue->front; + + if (queue->front == NULL) { + return false; + } + + if (queue->front == queue->rear) + queue->front = queue->rear = NULL; + else + queue->front = queue->front->next; + + queue->nr_ele--; + slab_free(&queue_factory.queue_ele_allocator, (void*)temp); + return true; +} + +bool enqueue(Queue* queue, uintptr_t key, void* data) +{ + QueueNode* temp = (struct QueueNode*)slab_alloc(&queue_factory.queue_ele_allocator); + if (temp == NULL) { + return false; + } + temp->key = key; + temp->data = data; + temp->next = NULL; + + if (queue->front == NULL && queue->rear == NULL) { + queue->front = queue->rear = temp; + } else { + queue->rear->next = temp; + queue->rear = temp; + } + + queue->nr_ele++; + return true; +} \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/softkernel/tools/rbtree.c b/Ubiquitous/XiZi_AIoT/softkernel/tools/rbtree.c new file mode 100644 index 000000000..b194882bb --- /dev/null +++ b/Ubiquitous/XiZi_AIoT/softkernel/tools/rbtree.c @@ -0,0 +1,467 @@ + +#include + +#include "assert.h" +#include "rbtree.h" + +struct RbtFactory { + TraceTag tag; + struct slab_allocator rbtnode_ele_allocator; +}; + +static struct RbtFactory rbt_factory; + +void module_rbt_factory_init(TraceTag* _softkernel_tag) +{ + CreateResourceTag(&rbt_factory.tag, _softkernel_tag, "GlobalRbtFactory", TRACER_SYSOBJECT, &rbt_factory); + slab_init(&rbt_factory.rbtnode_ele_allocator, sizeof(struct RbtNode), "RbtNodeAllocator"); +} + +void delete_case1(RbtTree* tree, RbtNode* node); +void delete_case2(RbtTree* tree, RbtNode* node); +void delete_case3(RbtTree* tree, RbtNode* node); +void delete_case4(RbtTree* tree, RbtNode* node); +void delete_case5(RbtTree* tree, RbtNode* node); +void delete_case6(RbtTree* tree, RbtNode* node); + +static inline enum rbt_type get_color(RbtNode* node) +{ + if (node == NULL) + return BLACK; + else + return node->color; +} + +static inline void set_color(enum rbt_type color, RbtNode* node) +{ + assert(node != NULL); + node->color = color; +} + +static inline RbtNode* get_parent(RbtNode* node) +{ + assert(node != NULL); + return node->parent; +} + +static inline void set_parent(RbtNode* parent, RbtNode* node) +{ + assert(node != NULL); + node->parent = parent; +} + +static int is_root(RbtNode* node) +{ + assert(node != NULL); + return (get_parent(node) == NULL); +} + +static inline int is_black(RbtNode* node) +{ + assert(node != NULL); + return (get_color(node) == BLACK); +} + +static inline int is_red(RbtNode* node) +{ + assert(node != NULL); + return (get_color(node) == RED); +} + +RbtNode* sibling(RbtNode* node) +{ + assert(node != NULL); + assert(node->parent != NULL); /* Root node has no sibling */ + if (node == node->parent->left) + return node->parent->right; + else + return node->parent->left; +} +static inline RbtNode* get_min(RbtNode* node) +{ + assert(node != NULL); + while (node->left) { + node = node->left; + } + return node; +} + +static inline RbtNode* get_max(RbtNode* node) +{ + assert(node != NULL); + while (node->right) { + node = node->right; + } + return node; +} + +RbtNode* rbtree_min(RbtTree* tree) +{ + if (tree->root == NULL) + return NULL; + else { + return get_min(tree->root); + } +} + +RbtNode* rbtree_max(RbtTree* tree) +{ + if (tree->root == NULL) + return NULL; + else { + return get_max(tree->root); + } +} + +RbtNode* rbtree_prev(RbtNode* node) +{ + assert(node != NULL); + if (node->left) { + return get_max(node->left); + } else { + RbtNode* parent; + while ((parent = get_parent(node)) && parent->left == node) { + node = parent; + } + return parent; + } +} + +RbtNode* rbtree_next(RbtNode* node) +{ + assert(node != NULL); + + if (node->right) + return get_min(node->right); + else { + RbtNode* parent = NULL; + while ((parent = get_parent(node)) != NULL && parent->right == node) { + node = parent; + } + return parent; + } +} + +RbtNode* rbtree_createnode(uintptr_t key, void* data) +{ + RbtNode* newnode = slab_alloc(&rbt_factory.rbtnode_ele_allocator); + if (newnode == NULL) + return NULL; + + newnode->key = key; + newnode->data = data; + newnode->parent = NULL; + newnode->left = NULL; + newnode->right = NULL; + return newnode; +} + +static inline int compare(uintptr_t key_a, uintptr_t key_b) +{ + if (key_a > key_b) + return 1; + else if (key_a == key_b) + return 0; + else + return -1; +} + +RbtNode* do_lookup(uintptr_t key, + RbtTree* tree, + RbtNode** pparent) +{ + RbtNode* current = tree->root; + + while (current) { + int ret = compare(current->key, key); + if (ret == 0) + return current; + else { + if (pparent != NULL) { + *pparent = current; + } + if (ret < 0) + current = current->right; + else + current = current->left; + } + } + return NULL; +} + +RbtNode* rbt_search(RbtTree* tree, uintptr_t key) +{ + RbtNode* node; + node = do_lookup(key, tree, NULL); + return node; +} + +static void set_child(RbtTree* tree, RbtNode* node, RbtNode* child) +{ + int ret = compare(node->key, child->key); + assert(ret != 0); + + if (ret > 0) { + node->left = child; + } else { + node->right = child; + } +} + +static void rotate_left(RbtNode* node, RbtTree* tree) +{ + RbtNode* p = node; + RbtNode* q = node->right; + RbtNode* parent = node->parent; + if (parent == NULL) { + tree->root = q; + } else { + if (parent->left == p) + parent->left = q; + else + parent->right = q; + } + set_parent(parent, q); + set_parent(q, p); + + p->right = q->left; + if (q->left) + set_parent(p, q->left); + q->left = p; +} + +static void rotate_right(RbtNode* node, RbtTree* tree) +{ + RbtNode* p = node; + RbtNode* q = node->left; /* can't be NULL */ + RbtNode* parent = get_parent(p); + + if (!is_root(p)) { + if (parent->left == p) + parent->left = q; + else + parent->right = q; + } else + tree->root = q; + set_parent(parent, q); + set_parent(q, p); + + p->left = q->right; + if (p->left) + set_parent(p, p->left); + q->right = p; +} + +void rbtree_init(RbtTree* tree) +{ + tree->root = NULL; + tree->nr_ele = 0; +} + +RbtNode* __rbtree_insert(RbtNode* node, RbtTree* tree) +{ + RbtNode* samenode = NULL; + RbtNode* parent = NULL; + + samenode = do_lookup(node->key, tree, &parent); + if (samenode != NULL) + return samenode; + + node->left = node->right = NULL; + set_color(RED, node); + set_parent(parent, node); + + if (parent == NULL) + tree->root = node; + else { + set_child(tree, parent, node); + } + + while ((parent = get_parent(node)) != NULL && parent->color == RED) { + RbtNode* grandpa = get_parent(parent); // grandpa must be existed + // because root is black ,and parent is red, + // parent can not be root of tree. and parent is red,so grandpa must be black + if (parent == grandpa->left) { + RbtNode* uncle = grandpa->right; + if (uncle && get_color(uncle) == RED) { + set_color(RED, grandpa); + set_color(BLACK, parent); + set_color(BLACK, uncle); + node = grandpa; + } else { + if (node == parent->right) { + rotate_left(parent, tree); + node = parent; + parent = get_parent(parent); + } + set_color(BLACK, parent); + set_color(RED, grandpa); + rotate_right(grandpa, tree); + } + + } else { + RbtNode* uncle = grandpa->left; + if (uncle && uncle->color == RED) { + set_color(RED, grandpa); + set_color(BLACK, parent); + set_color(BLACK, uncle); + node = grandpa; + } else { + if (node == parent->left) { + rotate_right(parent, tree); + node = parent; + parent = get_parent(node); + } + set_color(BLACK, parent); + set_color(RED, grandpa); + rotate_left(grandpa, tree); + } + } + } + + set_color(BLACK, tree->root); + return NULL; +} + +int rbt_insert(RbtTree* tree, uintptr_t key, void* data) +{ + if (rbt_search(tree, key) != NULL) { + return -2; + } + + RbtNode* node = rbtree_createnode(key, data); + RbtNode* samenode = NULL; + if (node == NULL) + return -1; + else + samenode = __rbtree_insert(node, tree); + + assert(samenode == NULL); + + tree->nr_ele++; + return 0; +} + +void replace_node(RbtTree* t, RbtNode* oldn, RbtNode* newn) +{ + if (oldn->parent == NULL) { + t->root = newn; + } else { + if (oldn == oldn->parent->left) + oldn->parent->left = newn; + else + oldn->parent->right = newn; + } + if (newn != NULL) { + newn->parent = oldn->parent; + } +} + +void delete_case1(RbtTree* tree, RbtNode* node) +{ + if (node->parent == NULL) + return; + else + delete_case2(tree, node); +} + +void delete_case2(RbtTree* tree, RbtNode* node) +{ + if (get_color(sibling(node)) == RED) { + node->parent->color = RED; + sibling(node)->color = BLACK; + if (node == node->parent->left) { + rotate_left(node->parent, tree); + } else { + rotate_right(node->parent, tree); + } + } + delete_case3(tree, node); +} + +void delete_case3(RbtTree* tree, RbtNode* node) +{ + if (node->parent->color == BLACK && get_color(sibling(node)) == BLACK && get_color(sibling(node)->right) == BLACK && get_color(sibling(node)->left) == BLACK) { + sibling(node)->color = RED; + delete_case1(tree, node->parent); + } else { + delete_case4(tree, node); + } +} + +void delete_case4(RbtTree* t, RbtNode* n) +{ + if (get_color(n->parent) == RED && get_color(sibling(n)) == BLACK && get_color(sibling(n)->left) == BLACK && get_color(sibling(n)->right) == BLACK) { + sibling(n)->color = RED; // sibling's two son is black ,so it can changed to red + n->parent->color = BLACK; + } else + delete_case5(t, n); +} + +void delete_case5(RbtTree* t, RbtNode* n) +{ + if (n == n->parent->left && get_color(sibling(n)) == BLACK && get_color(sibling(n)->left) == RED && get_color(sibling(n)->right) == BLACK) { + sibling(n)->color = RED; + sibling(n)->left->color = BLACK; + rotate_right(sibling(n), t); + } else if (n == n->parent->right && get_color(sibling(n)) == BLACK && get_color(sibling(n)->right) == RED && get_color(sibling(n)->left) == BLACK) { + sibling(n)->color = RED; + sibling(n)->right->color = BLACK; + rotate_left(sibling(n), t); + } + delete_case6(t, n); +} + +void delete_case6(RbtTree* t, RbtNode* n) +{ + sibling(n)->color = get_color(n->parent); + n->parent->color = BLACK; + if (n == n->parent->left) { + assert(get_color(sibling(n)->right) == RED); + sibling(n)->right->color = BLACK; + rotate_left(n->parent, t); + } else { + assert(get_color(sibling(n)->left) == RED); + sibling(n)->left->color = BLACK; + rotate_right(n->parent, t); + } +} + +void __rbtree_remove(RbtNode* node, RbtTree* tree) +{ + RbtNode* left = node->left; + RbtNode* right = node->right; + RbtNode* child = NULL; + if (left != NULL && right != NULL) { + RbtNode* next = get_min(right); + node->key = next->key; + node->data = next->data; + node = next; + } + + assert(node->left == NULL || node->right == NULL); + child = (node->right == NULL ? node->left : node->right); + if (get_color(node) == BLACK) { + set_color(get_color(child), node); + delete_case1(tree, node); + } + replace_node(tree, node, child); + if (node->parent == NULL && child != NULL) // node is root,root should be black + set_color(BLACK, child); + slab_free(&rbt_factory.rbtnode_ele_allocator, (void*)node); +} + +int rbt_delete(RbtTree* tree, uintptr_t key) +{ + RbtNode* node = do_lookup(key, tree, NULL); + if (node == NULL) + return -1; + else + __rbtree_remove(node, tree); + + tree->nr_ele--; + if (rbt_is_empty(tree)) { + assert(tree->root == NULL); + } + return 0; +} \ No newline at end of file