From 3e1479bdf0df3cfbb50045968dff4fc7239c7bad Mon Sep 17 00:00:00 2001 From: TXuian <1163589503@qq.com> Date: Thu, 31 Oct 2024 12:42:45 +0800 Subject: [PATCH] Valid 3 code version --- .../arch/arm/armv7-a/cortex-a9/core.h | 2 +- .../XiZi_AIoT/kernel_actracer/actracer.c | 4 + .../XiZi_AIoT/services/lib/ipc/libipc.c | 6 +- .../XiZi_AIoT/services/lib/ipc/libipc.h | 9 +- .../XiZi_AIoT/services/lib/ipc/session.h | 2 +- .../services/lib/usyscall/usyscall.c | 5 + .../services/lib/usyscall/usyscall.h | 5 +- .../XiZi_AIoT/softkernel/include/kalloc.h | 4 +- .../XiZi_AIoT/softkernel/include/ksemaphore.h | 25 +- .../XiZi_AIoT/softkernel/include/memspace.h | 3 +- .../XiZi_AIoT/softkernel/include/queue.h | 22 + .../XiZi_AIoT/softkernel/include/rbtree.h | 12 +- .../XiZi_AIoT/softkernel/include/share_page.h | 8 +- .../XiZi_AIoT/softkernel/include/syscall.h | 3 + .../XiZi_AIoT/softkernel/include/task.h | 5 + .../softkernel/init/softkernel_init.c | 1 + .../XiZi_AIoT/softkernel/memory/kalloc.c | 30 +- .../XiZi_AIoT/softkernel/memory/pagetable.c | 2 +- .../XiZi_AIoT/softkernel/memory/share_page.c | 15 + .../XiZi_AIoT/softkernel/syscall/Makefile | 3 +- .../softkernel/syscall/sys_close_session.c | 53 +- .../XiZi_AIoT/softkernel/syscall/sys_mmap.c | 6 +- .../softkernel/syscall/sys_poll_session.c | 95 +-- .../syscall/sys_register_as_server.c | 2 - .../softkernel/syscall/sys_semaphore.c | 2 +- .../softkernel/syscall/sys_wait_session.c | 65 ++ .../XiZi_AIoT/softkernel/syscall/sys_yield.c | 22 - .../XiZi_AIoT/softkernel/syscall/syscall.c | 3 + .../XiZi_AIoT/softkernel/task/memspace.c | 31 +- .../XiZi_AIoT/softkernel/task/semaphore.c | 63 +- Ubiquitous/XiZi_AIoT/softkernel/task/task.c | 29 +- .../XiZi_AIoT/softkernel/tools/Makefile | 2 +- Ubiquitous/XiZi_AIoT/softkernel/tools/queue.c | 75 ++ .../XiZi_AIoT/softkernel/tools/rbtree.c | 737 ++++++++++-------- 34 files changed, 831 insertions(+), 520 deletions(-) create mode 100644 Ubiquitous/XiZi_AIoT/softkernel/include/queue.h create mode 100644 Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_wait_session.c create mode 100644 Ubiquitous/XiZi_AIoT/softkernel/tools/queue.c 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 01c5623bf..1eb4bcf22 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 4 +#define NR_CPU 3 __attribute__((always_inline, optimize("O0"))) static inline uint32_t user_mode() { diff --git a/Ubiquitous/XiZi_AIoT/kernel_actracer/actracer.c b/Ubiquitous/XiZi_AIoT/kernel_actracer/actracer.c index ebbb85288..8dd1d8fc3 100644 --- a/Ubiquitous/XiZi_AIoT/kernel_actracer/actracer.c +++ b/Ubiquitous/XiZi_AIoT/kernel_actracer/actracer.c @@ -150,6 +150,10 @@ bool CreateResourceTag(TraceTag* new_tag, TraceTag* owner, char* name, tracemeta return false; } // assert(owner->meta->type == TRACER_OWNER); + if (type == TRACER_SERVER_IDENTITY_AC_RESOURCE && // + tracer_find_node_onestep(owner->meta, name) != NULL) { + return false; + } TracerNode* new_node = (TracerNode*)slab_alloc(&sys_tracer.node_allocator); if (new_node == NULL) { 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 d9ffcdf22..b3f86511b 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); diff --git a/Ubiquitous/XiZi_AIoT/services/lib/usyscall/usyscall.h b/Ubiquitous/XiZi_AIoT/services/lib/usyscall/usyscall.h index ca6e495a7..a1f1d0e15 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 { @@ -87,7 +89,8 @@ 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); diff --git a/Ubiquitous/XiZi_AIoT/softkernel/include/kalloc.h b/Ubiquitous/XiZi_AIoT/softkernel/include/kalloc.h index cdec72f3b..8b8d70771 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/include/kalloc.h +++ b/Ubiquitous/XiZi_AIoT/softkernel/include/kalloc.h @@ -34,7 +34,7 @@ Modification: struct MemUsage { TraceTag tag; - RbtNode* mem_block_root; + RbtTree mem_block_map; }; bool module_phymem_init(); @@ -47,6 +47,8 @@ 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 c71b258ab..1d0d999d0 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/include/memspace.h +++ b/Ubiquitous/XiZi_AIoT/softkernel/include/memspace.h @@ -50,7 +50,8 @@ struct MemSpace { /* trace node */ TraceTag tag; /* mem usage info */ - struct MemUsage mem_usage; + struct MemUsage kernspace_mem_usage; + struct MemUsage userspace_mem_usage; /* task memory resources */ struct TopLevelPageDirectory pgdir; // [phy] vm pgtbl base address diff --git a/Ubiquitous/XiZi_AIoT/softkernel/include/queue.h b/Ubiquitous/XiZi_AIoT/softkernel/include/queue.h new file mode 100644 index 000000000..8d6c5eb68 --- /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); +void dequeue(Queue* queue); +void 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 index 251bfb71f..5a5ace01e 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/include/rbtree.h +++ b/Ubiquitous/XiZi_AIoT/softkernel/include/rbtree.h @@ -21,11 +21,13 @@ typedef struct RbtNode { enum rbt_type color; } RbtNode; -struct RbtNode* rbt_insert(struct RbtNode* T, uintptr_t key, void* data); -struct RbtNode* rbt_delete(struct RbtNode* T, struct RbtNode* z); -struct RbtNode* rbt_search(struct RbtNode* root, int x); +typedef struct RbtTree { + RbtNode* root; +} RbtTree; -void preorder(struct RbtNode* root); -void levelorder(struct RbtNode* root); +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); \ 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..ab68d186a 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/include/share_page.h +++ b/Ubiquitous/XiZi_AIoT/softkernel/include/share_page.h @@ -32,12 +32,13 @@ Modification: #include #include "actracer.h" +#include "ksemaphore.h" #include "list.h" #include "task.h" /// @brief userland session info copy struct Session { - int id; + uintptr_t id; int capacity; int head; int tail; @@ -48,7 +49,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 +58,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; @@ -72,6 +73,7 @@ struct session_backend { 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; }; diff --git a/Ubiquitous/XiZi_AIoT/softkernel/include/syscall.h b/Ubiquitous/XiZi_AIoT/softkernel/include/syscall.h index 7d5da2bce..0a48bebe1 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__ @@ -105,6 +107,7 @@ 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); diff --git a/Ubiquitous/XiZi_AIoT/softkernel/include/task.h b/Ubiquitous/XiZi_AIoT/softkernel/include/task.h index 096a0613e..73eff6973 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" @@ -98,6 +99,10 @@ 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; diff --git a/Ubiquitous/XiZi_AIoT/softkernel/init/softkernel_init.c b/Ubiquitous/XiZi_AIoT/softkernel/init/softkernel_init.c index 4b371857f..d10f5bac6 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/init/softkernel_init.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/init/softkernel_init.c @@ -37,6 +37,7 @@ Modification: 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/memory/kalloc.c b/Ubiquitous/XiZi_AIoT/softkernel/memory/kalloc.c index 7233430fb..253b61956 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/memory/kalloc.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/memory/kalloc.c @@ -70,12 +70,12 @@ char* kalloc(uintptr_t size) void* kalloc_by_ownership(TraceTag owner, uintptr_t size) { void* new_mem = kalloc(size); - if (!new_mem) { + if (NULL == new_mem) { return NULL; } struct MemUsage* usage = GetSysObject(struct MemUsage, &owner); - usage->mem_block_root = rbt_insert(usage->mem_block_root, (uintptr_t)new_mem, NULL); + assert(0 == rbt_insert(&usage->mem_block_map, (uintptr_t)new_mem, NULL)); // DEBUG("%p %p %p %p\n", usage, usage->mem_block_root, usage->tag, new_mem); return new_mem; } @@ -89,9 +89,9 @@ 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_root, (uintptr_t)vaddr); + RbtNode* node = rbt_search(&usage->mem_block_map, (uintptr_t)vaddr); assert(NULL != node); - usage->mem_block_root = rbt_delete(usage->mem_block_root, node); + assert(0 == rbt_delete(&usage->mem_block_map, node->key)); return kfree(vaddr); } @@ -110,11 +110,33 @@ 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); + assert(0 == rbt_insert(&usage->mem_block_map, (uintptr_t)new_mem, 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/pagetable.c b/Ubiquitous/XiZi_AIoT/softkernel/memory/pagetable.c index 3c24e73f4..a49e3bfde 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/memory/pagetable.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/memory/pagetable.c @@ -161,7 +161,7 @@ static uintptr_t _resize_user_pgdir(struct MemSpace* pmemspace, uintptr_t old_si uintptr_t size_needed = ALIGNUP(new_size, PAGE_SIZE) - cur_size; // char* new_page = kalloc(size_needed); - char* new_page = kalloc_by_ownership(pmemspace->mem_usage.tag, 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; diff --git a/Ubiquitous/XiZi_AIoT/softkernel/memory/share_page.c b/Ubiquitous/XiZi_AIoT/softkernel/memory/share_page.c index a728cfb3f..304ace54b 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/memory/share_page.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/memory/share_page.c @@ -213,6 +213,14 @@ struct session_backend* create_share_pages(struct Thread* client, struct Thread* 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; /* alloc free memory as share memory */ @@ -220,6 +228,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 +238,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,6 +248,7 @@ 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; } @@ -253,6 +264,7 @@ struct session_backend* create_share_pages(struct Thread* client, struct Thread* session_backend->client_side.closed = false; doubleListNodeInit(&session_backend->client_side.node); doubleListAddOnBack(&session_backend->client_side.node, &client->cli_sess_listhead); + rbt_insert(&client->cli_sess_map, session_backend->session_id, &session_backend->client_side); // init server side session struct session_backend->server_side.buf_addr = server_vaddr; session_backend->server_side.capacity = true_capacity; @@ -261,6 +273,7 @@ struct session_backend* create_share_pages(struct Thread* client, struct Thread* session_backend->server_side.closed = false; doubleListNodeInit(&session_backend->server_side.node); doubleListAddOnBack(&session_backend->server_side.node, &server->svr_sess_listhead); + rbt_insert(&server->svr_sess_map, session_backend->session_id, &session_backend->server_side); server->memspace->mem_size += true_capacity; client->memspace->mem_size += true_capacity; @@ -306,6 +319,8 @@ int delete_share_pages(struct session_backend* session_backend) slab_free(SessionAllocator(), (void*)session_backend); } + ksemaphore_free(&xizi_task_manager.semaphore_pool, session_backend->client_sem_to_wait); + return 0; } 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..4914beda7 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_close_session.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_close_session.c @@ -46,35 +46,42 @@ 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; + rbt_delete(&cur_task->cli_sess_map, client_session_node->key); + xizi_share_page_manager.delete_share_pages(session_backend); } - 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; + rbt_delete(&cur_task->cli_sess_map, server_session_node->key); + xizi_share_page_manager.delete_share_pages(session_backend); } /* close this session */ diff --git a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_mmap.c b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_mmap.c index 28a2bbde5..77e3dd980 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_mmap.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_mmap.c @@ -54,15 +54,15 @@ 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, "ANON_MEMORY", TRACER_MEM_FROM_BUDDY_AC_RESOURCE, new_paddr); + CreateResourceTag(NULL, &cur_task->memspace->tag, "USER_MEMORY", TRACER_MEM_FROM_BUDDY_AC_RESOURCE, new_paddr); *paddr = (uintptr_t)new_paddr; } diff --git a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_poll_session.c b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_poll_session.c index 55451238e..77326755b 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; - } - 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); + 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; + + // 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); 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); + 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; + + dequeue(&cur_task->sessions_in_handle); + cur_userland_idx++; } + int nr_handled_calls = 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; + 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,18 @@ 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++; - } - - session_idx++; + enqueue(&cur_task->sessions_in_handle, 0, (void*)server_session); + dequeue(&cur_task->sessions_to_be_handle); } - 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); + 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..ff929b4ae 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 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_wait_session.c b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_wait_session.c new file mode 100644 index 000000000..d1f550ef7 --- /dev/null +++ b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_wait_session.c @@ -0,0 +1,65 @@ +/* + * 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); + 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) { + 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; + enqueue(&server_to_call->sessions_to_be_handle, 0, (void*)&session_backend->server_side); + 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..7e27ec232 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/syscall/syscall.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/syscall/syscall.c @@ -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 2f5b227b5..dcc9fb197 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/task/memspace.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/task/memspace.c @@ -62,10 +62,12 @@ struct MemSpace* alloc_memspace(char* name) return NULL; } - pmemspace->mem_usage.mem_block_root = NULL; - if (!CreateResourceTag(&pmemspace->mem_usage.tag, &pmemspace->tag, "MemUsage", TRACER_SYSOBJECT, (void*)&pmemspace->mem_usage)) { + rbtree_init(&pmemspace->kernspace_mem_usage.mem_block_map); + 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)) { 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; } return pmemspace; @@ -74,29 +76,26 @@ struct MemSpace* alloc_memspace(char* name) 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->mem_usage.mem_block_root; + 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->mem_usage.tag, (void*)rbt_node->key); - rbt_node = pmemspace->mem_usage.mem_block_root; + 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 */ diff --git a/Ubiquitous/XiZi_AIoT/softkernel/task/semaphore.c b/Ubiquitous/XiZi_AIoT/softkernel/task/semaphore.c index f1c5b5443..68395ca18 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; + sem_pool->next_sem_id = INVALID_SEM_ID + 1; slab_init(&sem_pool->allocator, sizeof(struct ksemaphore)); 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,34 @@ 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 */ + rbt_insert(&sem_pool->sem_pool_map, sem->id, sem); 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 +91,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 +106,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); @@ -105,6 +120,7 @@ bool ksemaphore_signal(struct XiziSemaphorePool* sem_pool, uint32_t sem_id) struct Thread* thd = CONTAINER_OF(sem->wait_list_guard.next, struct Thread, node); assert(thd != NULL && thd->state == BLOCKED); xizi_task_manager.task_unblock(thd); + // DEBUG("waking %s\n", thd->name); } } @@ -112,7 +128,20 @@ 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); @@ -128,8 +157,10 @@ bool ksemaphore_free(struct XiziSemaphorePool* sem_pool, uint32_t sem_id) 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; } diff --git a/Ubiquitous/XiZi_AIoT/softkernel/task/task.c b/Ubiquitous/XiZi_AIoT/softkernel/task/task.c index a80721069..e22d6e2f1 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/task/task.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/task/task.c @@ -117,8 +117,10 @@ int _task_return_sys_resources(struct Thread* ptask) assert(session_backend->server == ptask); // cut the connection from task to session server_session->closed = true; + rbt_delete(&ptask->svr_sess_map, session_backend->session_id); 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)) { @@ -128,6 +130,7 @@ int _task_return_sys_resources(struct Thread* ptask) assert(session_backend->client == ptask); // cut the connection from task to session client_session->closed = true; + rbt_delete(&ptask->cli_sess_map, session_backend->session_id); xizi_share_page_manager.delete_share_pages(session_backend); } @@ -174,13 +177,16 @@ static void _dealloc_task_cb(struct Thread* task) } } - /* free thread's kernel stack */ - if (task->thread_context.kern_stack_addr) { - kfree_by_ownership(task->memspace->mem_usage.tag, (char*)task->thread_context.kern_stack_addr); - } + // remove thread from used task list + task_node_leave_list(task); /* free memspace if needed to */ if (task->memspace != NULL) { + /* free thread's kernel stack */ + if (task->thread_context.kern_stack_addr) { + // kfree_by_ownership(task->memspace->kernspace_mem_usage.tag, (char*)task->thread_context.kern_stack_addr); + } + // awake deamon in this memspace if (task->memspace->thread_to_notify != NULL) { if (task->memspace->thread_to_notify != task) { @@ -195,6 +201,7 @@ static void _dealloc_task_cb(struct Thread* task) } 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 @@ -202,9 +209,6 @@ static void _dealloc_task_cb(struct Thread* task) } } - // 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); } @@ -227,15 +231,20 @@ static struct Thread* _new_task_cb(struct MemSpace* pmemspace) /* init basic task member */ doubleListNodeInit(&task->cli_sess_listhead); + rbtree_init(&task->cli_sess_map); doubleListNodeInit(&task->svr_sess_listhead); + rbtree_init(&task->svr_sess_map); + queue_init(&task->sessions_in_handle); + queue_init(&task->sessions_to_be_handle); /* when creating a new task, memspace will be freed outside during memory shortage */ - task->memspace = NULL; + assert(pmemspace != NULL); + task->memspace = pmemspace; /* 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_by_ownership(pmemspace->mem_usage.tag, USER_STACK_SIZE)) == NULL) { + 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 */ _dealloc_task_cb(task); return NULL; @@ -243,8 +252,6 @@ static struct Thread* _new_task_cb(struct MemSpace* pmemspace) /* from now on, _new_task_cb() will not generate error */ /* init vm */ - 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); diff --git a/Ubiquitous/XiZi_AIoT/softkernel/tools/Makefile b/Ubiquitous/XiZi_AIoT/softkernel/tools/Makefile index 5d2513c10..a6e840e59 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/tools/Makefile +++ b/Ubiquitous/XiZi_AIoT/softkernel/tools/Makefile @@ -1,4 +1,4 @@ -SRC_FILES := rbtree.c +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..3525c60dd --- /dev/null +++ b/Ubiquitous/XiZi_AIoT/softkernel/tools/queue.c @@ -0,0 +1,75 @@ + + +#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)); +} + +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; +} + +void dequeue(Queue* queue) +{ + struct QueueNode* temp = queue->front; + + if (queue->front == NULL) { + return; + } + + 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); +} + +void enqueue(Queue* queue, uintptr_t key, void* data) +{ + QueueNode* temp = (struct QueueNode*)slab_alloc(&queue_factory.queue_ele_allocator); + temp->key = key; + temp->data = data; + temp->next = NULL; + + if (queue->front == NULL && queue->rear == NULL) { + queue->front = queue->rear = temp; + queue->nr_ele++; + return; + } + + queue->rear->next = temp; + queue->rear = temp; + queue->nr_ele++; +} \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/softkernel/tools/rbtree.c b/Ubiquitous/XiZi_AIoT/softkernel/tools/rbtree.c index 31e1fd683..f136f22a2 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/tools/rbtree.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/tools/rbtree.c @@ -1,387 +1,454 @@ + +#include + +#include "assert.h" #include "rbtree.h" -#include "log.h" -#include "object_allocator.h" struct RbtFactory { TraceTag tag; - struct slab_allocator queue_ele_allocator; struct slab_allocator rbtnode_ele_allocator; }; -struct Queue { - struct RbtNode* key; - struct Queue* next; -}; - 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.queue_ele_allocator, sizeof(struct Queue)); slab_init(&rbt_factory.rbtnode_ele_allocator, sizeof(struct RbtNode)); } -struct Queue* front = NULL; -struct Queue* rear = NULL; +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); -struct RbtNode* pfront() +static inline enum rbt_type get_color(RbtNode* node) { - struct RbtNode* key; - key = front->key; - return key; -} - -int isempty() -{ - if (front == NULL) - return 1; - + if (node == NULL) + return BLACK; else - return 0; + return node->color; } -void dequeue() +static inline void set_color(enum rbt_type color, RbtNode* node) { - if (isempty()) - return; - - struct Queue* temp = front; - front = front->next; - slab_free(&rbt_factory.queue_ele_allocator, (void*)temp); + assert(node != NULL); + node->color = color; } -void enqueue(struct RbtNode* key) +static inline RbtNode* get_parent(RbtNode* node) { - struct Queue* temp = (struct Queue*)slab_alloc(&rbt_factory.queue_ele_allocator); - temp->key = key; - temp->next = NULL; - - if (front == NULL && rear == NULL) { - front = rear = temp; - return; - } - - rear->next = temp; - rear = temp; + assert(node != NULL); + return node->parent; } -void levelorder(struct RbtNode* root) +static inline void set_parent(RbtNode* parent, RbtNode* node) { - if (root == NULL) - return; - - enqueue(root); - - while (!isempty()) { - struct RbtNode* current = pfront(); - DEBUG("%d ", current->key); - - if (current->left != NULL) - enqueue(current->left); - - if (current->right != NULL) - enqueue(current->right); - - dequeue(); - } + assert(node != NULL); + node->parent = parent; } -void LeftRotate(struct RbtNode** T, struct RbtNode** x) +static int is_root(RbtNode* node) { - struct RbtNode* y = (*x)->right; - (*x)->right = y->left; + assert(node != NULL); + return (get_parent(node) == NULL); +} - if (y->left != NULL) - y->left->parent = *x; +static inline int is_black(RbtNode* node) +{ + assert(node != NULL); + return (get_color(node) == BLACK); +} - y->parent = (*x)->parent; - - if ((*x)->parent == NULL) - *T = y; - - else if (*x == (*x)->parent->left) - (*x)->parent->left = y; +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 - (*x)->parent->right = y; - - y->left = *x; - - (*x)->parent = y; + return node->parent->left; } -void RightRotate(struct RbtNode** T, struct RbtNode** x) +static inline RbtNode* get_min(RbtNode* node) { - struct RbtNode* y = (*x)->left; - (*x)->left = y->right; - - if (y->right != NULL) - y->right->parent = *x; - - y->parent = (*x)->parent; - - if ((*x)->parent == NULL) - *T = y; - - else if ((*x) == (*x)->parent->left) - (*x)->parent->left = y; - - else - (*x)->parent->right = y; - - y->right = *x; - (*x)->parent = y; -} - -void RB_insert_fixup(struct RbtNode** T, struct RbtNode** z) -{ - struct RbtNode* grandparent = NULL; - struct RbtNode* parentpt = NULL; - - while (((*z) != *T) && ((*z)->color != BLACK) && ((*z)->parent->color == RED)) { - parentpt = (*z)->parent; - grandparent = (*z)->parent->parent; - - if (parentpt == grandparent->left) { - struct RbtNode* uncle = grandparent->right; - - if (uncle != NULL && uncle->color == RED) { - grandparent->color = RED; - parentpt->color = BLACK; - uncle->color = BLACK; - *z = grandparent; - } - - else { - if ((*z) == parentpt->right) { - LeftRotate(T, &parentpt); - (*z) = parentpt; - parentpt = (*z)->parent; - } - - RightRotate(T, &grandparent); - parentpt->color = BLACK; - grandparent->color = RED; - (*z) = parentpt; - } - } - - else { - struct RbtNode* uncle = grandparent->left; - - if (uncle != NULL && uncle->color == RED) { - grandparent->color = RED; - parentpt->color = BLACK; - uncle->color = BLACK; - (*z) = grandparent; - } - - else { - if ((*z) == parentpt->left) { - RightRotate(T, &parentpt); - (*z) = parentpt; - parentpt = (*z)->parent; - } - - LeftRotate(T, &grandparent); - parentpt->color = BLACK; - grandparent->color = RED; - (*z) = parentpt; - } - } + assert(node != NULL); + while (node->left) { + node = node->left; } - (*T)->color = BLACK; + return node; } -struct RbtNode* rbt_insert(struct RbtNode* T, uintptr_t key, void* data) +static inline RbtNode* get_max(RbtNode* node) { - struct RbtNode* z = (struct RbtNode*)slab_alloc(&rbt_factory.rbtnode_ele_allocator); - z->key = key; - z->data = data; - z->left = NULL; - z->right = NULL; - z->parent = NULL; - z->color = RED; - - struct RbtNode* y = NULL; - struct RbtNode* x = T; // root - - while (x != NULL) { - y = x; - if (z->key < x->key) - x = x->left; - - else - x = x->right; + assert(node != NULL); + while (node->right) { + node = node->right; } - z->parent = y; - - if (y == NULL) - T = z; - - else if (z->key < y->key) - y->left = z; - - else - y->right = z; - - RB_insert_fixup(&T, &z); - - return T; + return node; } -void preorder(struct RbtNode* root) +RbtNode* rbtree_min(RbtTree* tree) { - if (root == NULL) - return; - - DEBUG("%d ", root->key); - preorder(root->left); - preorder(root->right); -} - -struct RbtNode* Tree_minimum(struct RbtNode* RbtNode) -{ - while (RbtNode->left != NULL) - RbtNode = RbtNode->left; - - return RbtNode; -} - -void RB_delete_fixup(struct RbtNode** T, struct RbtNode** x) -{ - while ((*x) != *T && (*x)->color == BLACK) { - if ((*x) == (*x)->parent->left) { - struct RbtNode* w = (*x)->parent->right; - - if (w->color == RED) { - w->color = BLACK; - (*x)->parent->color = BLACK; - LeftRotate(T, &((*x)->parent)); - w = (*x)->parent->right; - } - - if (w->left->color == BLACK && w->right->color == BLACK) { - w->color = RED; - (*x) = (*x)->parent; - } - - else { - if (w->right->color == BLACK) { - w->left->color = BLACK; - w->color = RED; - RightRotate(T, &w); - w = (*x)->parent->right; - } - - w->color = (*x)->parent->color; - (*x)->parent->color = BLACK; - w->right->color = BLACK; - LeftRotate(T, &((*x)->parent)); - (*x) = *T; - } - } - - else { - struct RbtNode* w = (*x)->parent->left; - - if (w->color == RED) { - w->color = BLACK; - (*x)->parent->color = BLACK; - RightRotate(T, &((*x)->parent)); - w = (*x)->parent->left; - } - - if (w->right->color == BLACK && w->left->color == BLACK) { - w->color = RED; - (*x) = (*x)->parent; - } - - else { - if (w->left->color == BLACK) { - w->right->color = BLACK; - w->color = RED; - LeftRotate(T, &w); - w = (*x)->parent->left; - } - - w->color = (*x)->parent->color; - (*x)->parent->color = BLACK; - w->left->color = BLACK; - RightRotate(T, &((*x)->parent)); - (*x) = *T; - } - } - } - (*x)->color = BLACK; -} - -void RB_transplat(struct RbtNode** T, struct RbtNode** u, struct RbtNode** v) -{ - if ((*u)->parent == NULL) - *T = *v; - - else if ((*u) == (*u)->parent->left) - (*u)->parent->left = *v; - else - (*u)->parent->right = *v; - - if ((*v) != NULL) - (*v)->parent = (*u)->parent; -} - -struct RbtNode* rbt_delete(struct RbtNode* T, struct RbtNode* z) -{ - struct RbtNode* y = z; - enum rbt_type yoc; - yoc = z->color; // y's original color - - struct RbtNode* x; - - if (z->left == NULL) { - x = z->right; - RB_transplat(&T, &z, &(z->right)); - } - - else if (z->right == NULL) { - x = z->left; - RB_transplat(&T, &z, &(z->left)); - } - + if (tree->root == NULL) + return NULL; else { - y = Tree_minimum(z->right); - yoc = y->color; - x = y->right; - - if (y->parent == z) - x->parent = y; - - else { - RB_transplat(&T, &y, &(y->right)); - y->right = z->right; - y->right->parent = y; - } - - RB_transplat(&T, &z, &y); - y->left = z->left; - y->left->parent = y; - y->color = z->color; + return get_min(tree->root); } - - if (yoc == BLACK) - RB_delete_fixup(&T, &x); - - slab_free(&rbt_factory.rbtnode_ele_allocator, (void*)z); - return T; } -struct RbtNode* rbt_search(struct RbtNode* root, int x) +RbtNode* rbtree_max(RbtTree* tree) { - if (root == NULL || root->key == x) - return root; + if (tree->root == NULL) + return NULL; + else { + return get_max(tree->root); + } +} - if (root->key > x) - return rbt_search(root->left, x); +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 rbt_search(root->right, x); + 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; +} + +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) +{ + RbtNode* node = rbtree_createnode(key, data); + RbtNode* samenode = NULL; + if (node == NULL) + return -1; + else + samenode = __rbtree_insert(node, tree); + if (samenode != NULL) + return -2; + 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); + return 0; } \ No newline at end of file