Valid 3 code version

This commit is contained in:
TXuian 2024-10-31 12:42:45 +08:00
parent 7b6c93d391
commit 3e1479bdf0
34 changed files with 831 additions and 520 deletions

View File

@ -74,7 +74,7 @@ Modification:
#include "cortex_a9.h" #include "cortex_a9.h"
#define NR_CPU 4 #define NR_CPU 3
__attribute__((always_inline, optimize("O0"))) static inline uint32_t user_mode() __attribute__((always_inline, optimize("O0"))) static inline uint32_t user_mode()
{ {

View File

@ -150,6 +150,10 @@ bool CreateResourceTag(TraceTag* new_tag, TraceTag* owner, char* name, tracemeta
return false; return false;
} }
// assert(owner->meta->type == TRACER_OWNER); // 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); TracerNode* new_node = (TracerNode*)slab_alloc(&sys_tracer.node_allocator);
if (new_node == NULL) { if (new_node == NULL) {

View File

@ -131,14 +131,14 @@ bool ipc_msg_get_nth_arg(struct IpcMsg* msg, const int arg_num, void* data, cons
return true; 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.magic = IPC_MSG_MAGIC;
msg->header.valid = 1; msg->header.valid = 1;
msg->header.done = 0; msg->header.done = 0;
while (msg->header.done == 0) { while (msg->header.done == 0) {
/// @todo syscall yield with prio decrease /// @todo syscall yield with prio decrease
yield(SYS_TASK_YIELD_BLOCK_IPC); wait_session_call(session);
} }
assert(msg->header.done == 1); assert(msg->header.done == 1);
} }
@ -155,7 +155,7 @@ int ipc_session_wait(struct Session* session)
struct IpcMsg* msg = IPCSESSION_MSG(session); struct IpcMsg* msg = IPCSESSION_MSG(session);
while (msg->header.done == 0) { while (msg->header.done == 0) {
/// @todo syscall yield with prio decrease /// @todo syscall yield with prio decrease
yield(SYS_TASK_YIELD_BLOCK_IPC); wait_session_call(session);
} }
assert(msg->header.done == 1); assert(msg->header.done == 1);
return msg->header.ret_val; return msg->header.ret_val;

View File

@ -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); 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_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); 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); void ipc_msg_send_nowait(struct IpcMsg* msg);
int ipc_session_wait(struct Session* session); 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__)); \ 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__)); \ 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); \ 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__)); \ ret = IPC_MSG_ARGS_COPY_GET_FUNC(ipc_name)(msg, _VA_FRONT_ARG##argc(__VA_ARGS__)); \
int32_t res = 0; \ int32_t res = 0; \
ipc_msg_get_return(msg, &res); \ ipc_msg_get_return(msg, &res); \
@ -278,9 +278,10 @@ uintptr_t _ipc_buf_to_addr(char* buf);
char addr_buf[17]; \ char addr_buf[17]; \
_ipc_addr_to_buf((uintptr_t)msg, addr_buf); \ _ipc_addr_to_buf((uintptr_t)msg, addr_buf); \
char* param[] = { #ipc_name, addr_buf, NULL }; \ char* param[] = { #ipc_name, addr_buf, NULL }; \
msg->header.handling = 1; \
int tid = thread(IPC_THREAD_SERVE(ipc_name), #ipc_name, param); \ int tid = thread(IPC_THREAD_SERVE(ipc_name), #ipc_name, param); \
if (tid > 0) { \ if (tid <= 0) { \
msg->header.handling = 1; \ msg->header.handling = 0; \
} \ } \
return 0; \ return 0; \
} }

View File

@ -36,7 +36,7 @@ Modification:
#include "libserial.h" #include "libserial.h"
struct Session { struct Session {
int id; uintptr_t id;
int capacity; int capacity;
int head; int head;
int tail; int tail;

View File

@ -72,6 +72,11 @@ int close_session(struct Session* session)
return syscall(SYSCALL_CLOSE_SESSION, (intptr_t)session, 0, 0, 0); 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) int get_memblock_info(sys_state_info* info)
{ {
return syscall(SYSCALL_SYS_STATE, SYS_STATE_MEMBLOCK_INFO, (intptr_t)info, 0, 0); return syscall(SYSCALL_SYS_STATE, SYS_STATE_MEMBLOCK_INFO, (intptr_t)info, 0, 0);

View File

@ -35,6 +35,8 @@
#define SYSCALL_SEMAPHORE 13 // semaphore related operations #define SYSCALL_SEMAPHORE 13 // semaphore related operations
#define SYSCALL_SLEEP 14 // sleep #define SYSCALL_SLEEP 14 // sleep
#define SYSCALL_WAIT_SESSION 15
// clang-format on // clang-format on
typedef enum { typedef enum {
@ -87,7 +89,8 @@ int kill(int pid);
int register_server(char* name); int register_server(char* name);
int session(char* path, int capacity, struct Session* user_session); 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 close_session(struct Session* session);
int register_irq(int irq, int opcode); int register_irq(int irq, int opcode);

View File

@ -34,7 +34,7 @@ Modification:
struct MemUsage { struct MemUsage {
TraceTag tag; TraceTag tag;
RbtNode* mem_block_root; RbtTree mem_block_map;
}; };
bool module_phymem_init(); bool module_phymem_init();
@ -47,6 +47,8 @@ bool kfree_by_ownership(TraceTag owner, void* vaddr);
char* raw_alloc(size_t size); char* raw_alloc(size_t size);
bool raw_free(char* paddr); 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(); void show_phymem_info();

View File

@ -23,6 +23,14 @@
#include "list.h" #include "list.h"
#include "object_allocator.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 /// @warning this is no in use
enum { enum {
@ -30,8 +38,8 @@ enum {
}; };
struct ksemaphore { struct ksemaphore {
uint32_t id; sem_id_t id;
int val; sem_val_t val;
/* list of waiting threads */ /* list of waiting threads */
struct double_list_node wait_list_guard; struct double_list_node wait_list_guard;
/* list to manage semaphores */ /* list to manage semaphores */
@ -40,12 +48,17 @@ struct ksemaphore {
}; };
struct XiziSemaphorePool { struct XiziSemaphorePool {
uint32_t next_sem_id; sem_id_t next_sem_id;
struct slab_allocator allocator; struct slab_allocator allocator;
struct double_list_node sem_list_guard; struct double_list_node sem_list_guard;
RbtTree sem_pool_map;
sem_val_t nr_sem;
}; };
void semaphore_pool_init(struct XiziSemaphorePool* sem_pool); void semaphore_pool_init(struct XiziSemaphorePool* sem_pool);
int ksemaphore_alloc(struct XiziSemaphorePool* sem_pool, int val); sem_id_t ksemaphore_alloc(struct XiziSemaphorePool* sem_pool, sem_val_t val);
bool ksemaphore_free(struct XiziSemaphorePool* sem_pool, uint32_t sem_id); bool ksemaphore_free(struct XiziSemaphorePool* sem_pool, sem_id_t sem_id);
bool ksemaphore_signal(struct XiziSemaphorePool* sem_pool, uint32_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);

View File

@ -50,7 +50,8 @@ struct MemSpace {
/* trace node */ /* trace node */
TraceTag tag; TraceTag tag;
/* mem usage info */ /* mem usage info */
struct MemUsage mem_usage; struct MemUsage kernspace_mem_usage;
struct MemUsage userspace_mem_usage;
/* task memory resources */ /* task memory resources */
struct TopLevelPageDirectory pgdir; // [phy] vm pgtbl base address struct TopLevelPageDirectory pgdir; // [phy] vm pgtbl base address

View File

@ -0,0 +1,22 @@
#pragma once
#include <stddef.h>
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);

View File

@ -21,11 +21,13 @@ typedef struct RbtNode {
enum rbt_type color; enum rbt_type color;
} RbtNode; } RbtNode;
struct RbtNode* rbt_insert(struct RbtNode* T, uintptr_t key, void* data); typedef struct RbtTree {
struct RbtNode* rbt_delete(struct RbtNode* T, struct RbtNode* z); RbtNode* root;
struct RbtNode* rbt_search(struct RbtNode* root, int x); } RbtTree;
void preorder(struct RbtNode* root); void rbtree_init(RbtTree* tree);
void levelorder(struct RbtNode* root); 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); void module_rbt_factory_init(TraceTag* _softkernel_tag);

View File

@ -32,12 +32,13 @@ Modification:
#include <stdint.h> #include <stdint.h>
#include "actracer.h" #include "actracer.h"
#include "ksemaphore.h"
#include "list.h" #include "list.h"
#include "task.h" #include "task.h"
/// @brief userland session info copy /// @brief userland session info copy
struct Session { struct Session {
int id; uintptr_t id;
int capacity; int capacity;
int head; int head;
int tail; int tail;
@ -48,7 +49,7 @@ struct Session {
#define CLIENT_SESSION_BACKEND(session) CONTAINER_OF(session, struct session_backend, client_side) #define CLIENT_SESSION_BACKEND(session) CONTAINER_OF(session, struct session_backend, client_side)
struct server_session { 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; uintptr_t buf_addr;
int capacity; int capacity;
int head; int head;
@ -57,7 +58,7 @@ struct server_session {
}; };
struct client_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; uintptr_t buf_addr;
int capacity; int capacity;
bool closed; bool closed;
@ -72,6 +73,7 @@ struct session_backend {
struct Thread* client; // client of this pipe struct Thread* client; // client of this pipe
struct Thread* server; // server of this pipe struct Thread* server; // server of this pipe
sem_id_t client_sem_to_wait;
uintptr_t buf_kernel_addr; uintptr_t buf_kernel_addr;
}; };

View File

@ -49,6 +49,8 @@ Modification:
#define SYSCALL_SEMAPHORE 13 // semaphore related operations #define SYSCALL_SEMAPHORE 13 // semaphore related operations
#define SYSCALL_SLEEP 14 // sleep #define SYSCALL_SLEEP 14 // sleep
#define SYSCALL_WAIT_SESSION 15
// clang-format on // clang-format on
#ifndef __ASSEMBLER__ #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_connect_session(char* path, int capacity, struct Session* user_session);
int sys_poll_session(struct Session* userland_session_arr, int arr_capacity); int sys_poll_session(struct Session* userland_session_arr, int arr_capacity);
int sys_close_session(struct Thread* task, struct Session* session); 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_exec(char* img_start, char* name, char** argv);
int sys_state(sys_state_option option, sys_state_info* info); int sys_state(sys_state_option option, sys_state_info* info);

View File

@ -37,6 +37,7 @@ Modification:
#include "memspace.h" #include "memspace.h"
#include "object_allocator.h" #include "object_allocator.h"
#include "pagetable.h" #include "pagetable.h"
#include "queue.h"
#include "share_page.h" #include "share_page.h"
#include "spinlock.h" #include "spinlock.h"
@ -98,6 +99,10 @@ struct Thread {
/* task communication resources */ /* task communication resources */
struct double_list_node cli_sess_listhead; struct double_list_node cli_sess_listhead;
struct double_list_node svr_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; struct TraceTag server_identifier;
bool advance_unblock; bool advance_unblock;

View File

@ -37,6 +37,7 @@ Modification:
bool softkernel_init(TraceTag* _hardkernel_tag, struct TraceTag* _softkernel_tag) bool softkernel_init(TraceTag* _hardkernel_tag, struct TraceTag* _softkernel_tag)
{ {
module_rbt_factory_init(_softkernel_tag); module_rbt_factory_init(_softkernel_tag);
module_queue_factory_init(_softkernel_tag);
struct TraceTag server_identifier_owner; struct TraceTag server_identifier_owner;
CreateResourceTag(&server_identifier_owner, _softkernel_tag, "server-identifier", TRACER_OWNER, NULL); CreateResourceTag(&server_identifier_owner, _softkernel_tag, "server-identifier", TRACER_OWNER, NULL);

View File

@ -70,12 +70,12 @@ char* kalloc(uintptr_t size)
void* kalloc_by_ownership(TraceTag owner, uintptr_t size) void* kalloc_by_ownership(TraceTag owner, uintptr_t size)
{ {
void* new_mem = kalloc(size); void* new_mem = kalloc(size);
if (!new_mem) { if (NULL == new_mem) {
return NULL; return NULL;
} }
struct MemUsage* usage = GetSysObject(struct MemUsage, &owner); 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); // DEBUG("%p %p %p %p\n", usage, usage->mem_block_root, usage->tag, new_mem);
return new_mem; return new_mem;
} }
@ -89,9 +89,9 @@ bool kfree_by_ownership(TraceTag owner, void* vaddr)
{ {
struct MemUsage* usage = GetSysObject(struct MemUsage, &owner); struct MemUsage* usage = GetSysObject(struct MemUsage, &owner);
// DEBUG("%p %p %p %p\n", usage, usage->mem_block_root, usage->tag, vaddr); // 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); 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); return kfree(vaddr);
} }
@ -110,11 +110,33 @@ char* raw_alloc(size_t size)
return mem_alloc; 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) bool raw_free(char* paddr)
{ {
return KBuddyFree(&user_phy_freemem_buddy, 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() void show_phymem_info()
{ {
KFreePagesInfo(&user_phy_freemem_buddy); KFreePagesInfo(&user_phy_freemem_buddy);

View File

@ -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; 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->mem_usage.tag, size_needed); char* new_page = kalloc_by_ownership(pmemspace->kernspace_mem_usage.tag, size_needed);
if (new_page == NULL) { if (new_page == NULL) {
ERROR("No memory\n"); ERROR("No memory\n");
return cur_size; return cur_size;

View File

@ -213,6 +213,14 @@ struct session_backend* create_share_pages(struct Thread* client, struct Thread*
return NULL; 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 true_capacity = ALIGNUP(capacity, PAGE_SIZE);
int nr_pages = true_capacity / PAGE_SIZE; int nr_pages = true_capacity / PAGE_SIZE;
/* alloc free memory as share memory */ /* 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)) { if (UNLIKELY(kern_vaddr == (uintptr_t)NULL)) {
ERROR("No memory for session\n"); ERROR("No memory for session\n");
slab_free(SessionAllocator(), session_backend); slab_free(SessionAllocator(), session_backend);
ksemaphore_free(&xizi_task_manager.semaphore_pool, new_sem_id);
return NULL; return NULL;
} }
@ -229,6 +238,7 @@ struct session_backend* create_share_pages(struct Thread* client, struct Thread*
if (UNLIKELY(client_vaddr == (uintptr_t)NULL)) { if (UNLIKELY(client_vaddr == (uintptr_t)NULL)) {
kfree((char*)kern_vaddr); kfree((char*)kern_vaddr);
slab_free(SessionAllocator(), session_backend); slab_free(SessionAllocator(), session_backend);
ksemaphore_free(&xizi_task_manager.semaphore_pool, new_sem_id);
return NULL; 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); unmap_task_share_pages(client, client_vaddr, nr_pages);
kfree((char*)kern_vaddr); kfree((char*)kern_vaddr);
slab_free(SessionAllocator(), session_backend); slab_free(SessionAllocator(), session_backend);
ksemaphore_free(&xizi_task_manager.semaphore_pool, new_sem_id);
return NULL; return NULL;
} }
@ -253,6 +264,7 @@ struct session_backend* create_share_pages(struct Thread* client, struct Thread*
session_backend->client_side.closed = false; session_backend->client_side.closed = false;
doubleListNodeInit(&session_backend->client_side.node); doubleListNodeInit(&session_backend->client_side.node);
doubleListAddOnBack(&session_backend->client_side.node, &client->cli_sess_listhead); 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 // init server side session struct
session_backend->server_side.buf_addr = server_vaddr; session_backend->server_side.buf_addr = server_vaddr;
session_backend->server_side.capacity = true_capacity; 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; session_backend->server_side.closed = false;
doubleListNodeInit(&session_backend->server_side.node); doubleListNodeInit(&session_backend->server_side.node);
doubleListAddOnBack(&session_backend->server_side.node, &server->svr_sess_listhead); 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; server->memspace->mem_size += true_capacity;
client->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); slab_free(SessionAllocator(), (void*)session_backend);
} }
ksemaphore_free(&xizi_task_manager.semaphore_pool, session_backend->client_sem_to_wait);
return 0; return 0;
} }

View File

@ -12,6 +12,7 @@ SRC_FILES := syscall.c \
sys_state.c \ sys_state.c \
sys_mmap.c \ sys_mmap.c \
sys_kill.c \ sys_kill.c \
sys_semaphore.c sys_semaphore.c \
sys_wait_session.c
include $(KERNEL_ROOT)/compiler.mk include $(KERNEL_ROOT)/compiler.mk

View File

@ -46,35 +46,42 @@ int sys_close_session(struct Thread* cur_task, struct Session* session)
return -1; return -1;
} }
/* check if session is a client one or a server one */
struct session_backend* session_backend = NULL; struct session_backend* session_backend = NULL;
struct client_session* client_session = NULL; /* check if session is a client one or a server one */
DOUBLE_LIST_FOR_EACH_ENTRY(client_session, &cur_task->cli_sess_listhead, node) RbtNode* client_session_node = rbt_search(&cur_task->cli_sess_map, session->id);
{ if (client_session_node != NULL) {
if ((uintptr_t)session->buf == client_session->buf_addr) { struct client_session* client_session = (struct client_session*)client_session_node->data;
session_backend = CLIENT_SESSION_BACKEND(client_session); if (CLIENT_SESSION_BACKEND(client_session)->session_id != session->id || //
assert(session_backend->client == cur_task); client_session->buf_addr != (uintptr_t)session->buf) {
assert(client_session->closed == false); ERROR("Error closing session from %s: Invalid session\n", cur_task->name);
client_session->closed = true; return -1;
xizi_share_page_manager.delete_share_pages(session_backend);
break;
} }
/* 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)) { RbtNode* server_session_node = rbt_search(&cur_task->svr_sess_map, session->id);
struct server_session* server_session = NULL; if (server_session_node != NULL) {
DOUBLE_LIST_FOR_EACH_ENTRY(server_session, &cur_task->svr_sess_listhead, node) struct server_session* server_session = (struct server_session*)server_session_node->data;
{ if (SERVER_SESSION_BACKEND(server_session)->session_id != session->id || //
if ((uintptr_t)session->buf == server_session->buf_addr) { server_session->buf_addr != (uintptr_t)session->buf) {
session_backend = SERVER_SESSION_BACKEND(server_session); ERROR("Error closing session from %s: Invalid session\n", cur_task->name);
assert(session_backend->server == cur_task); return -1;
assert(server_session->closed == false);
server_session->closed = true;
xizi_share_page_manager.delete_share_pages(session_backend);
break;
}
} }
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 */ /* close this session */

View File

@ -54,15 +54,15 @@ int sys_mmap(uintptr_t* vaddr, uintptr_t* paddr, int len, int is_dev)
} }
} else { } else {
uintptr_t load_vaddr = *vaddr; 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) { if (new_paddr == NULL) {
return -1; 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) { 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; 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; *paddr = (uintptr_t)new_paddr;
} }

View File

@ -34,14 +34,7 @@ Modification:
#include "syscall.h" #include "syscall.h"
#include "task.h" #include "task.h"
#define IPCSESSION_MSG(session) ((struct IpcMsg*)((char*)((session)->buf) + (session)->head)) extern bool ksemaphore_wait(struct XiziSemaphorePool* sem_pool, struct Thread* thd, sem_id_t sem_id);
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;
}
int sys_poll_session(struct Session* userland_session_arr, int arr_capacity) int sys_poll_session(struct Session* userland_session_arr, int arr_capacity)
{ {
struct Thread* cur_task = cur_cpu()->task; 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; return -1;
} }
struct double_list_node* cur_node = NULL;
struct server_session* server_session = NULL;
/* update old sessions */ /* update old sessions */
for (int i = 0; i < arr_capacity; i++) { int cur_userland_idx = 0;
if (UNLIKELY(userland_session_arr[i].buf == NULL)) { while (!queue_is_empty(&cur_task->sessions_in_handle)) {
break; struct server_session* server_session = (struct server_session*)queue_front(&cur_task->sessions_in_handle)->data;
}
cur_node = cur_task->svr_sess_listhead.next; // wrong session info
server_session = CONTAINER_OF(cur_node, struct server_session, node); if (userland_session_arr[cur_userland_idx].id != SERVER_SESSION_BACKEND(server_session)->session_id || //
if (UNLIKELY(server_session->buf_addr != (uintptr_t)userland_session_arr[i].buf)) { (uintptr_t)userland_session_arr[cur_userland_idx].buf != server_session->buf_addr) {
ERROR("mismatched old session addr, user buf: %x, server buf: %x\n", userland_session_arr[i].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; return -1;
} }
// update session_backend // update session_backend
// if current session is handled ksemaphore_signal(&xizi_task_manager.semaphore_pool, SERVER_SESSION_BACKEND(server_session)->client_sem_to_wait);
if (server_session->head != userland_session_arr[i].head) {
struct Thread* client = SERVER_SESSION_BACKEND(server_session)->client; server_session->head = userland_session_arr[cur_userland_idx].head;
if (client->state == BLOCKED) { server_session->tail = userland_session_arr[cur_userland_idx].tail;
xizi_task_manager.task_unblock(client); userland_session_arr[cur_userland_idx].buf = NULL;
} else { userland_session_arr[cur_userland_idx].id = -1;
client->advance_unblock = true;
} dequeue(&cur_task->sessions_in_handle);
} cur_userland_idx++;
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);
} }
int nr_handled_calls = cur_userland_idx;
/* poll with new sessions */ /* poll with new sessions */
int nr_sessions_need_to_handle = 0; cur_userland_idx = 0;
bool has_middle_delete = false; while (!queue_is_empty(&cur_task->sessions_to_be_handle)) {
int session_idx = 0; if (cur_userland_idx == arr_capacity) {
DOUBLE_LIST_FOR_EACH_ENTRY(server_session, &cur_task->svr_sess_listhead, node)
{
if (session_idx >= arr_capacity) {
break; 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) { if (SERVER_SESSION_BACKEND(server_session)->client_side.closed) {
// client had closed it, then server will close it too // client had closed it, then server will close it too
struct session_backend* session_backend = SERVER_SESSION_BACKEND(server_session); 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); assert(server_session->closed == false);
server_session->closed = true; server_session->closed = true;
xizi_share_page_manager.delete_share_pages(session_backend); xizi_share_page_manager.delete_share_pages(session_backend);
// signal that there is a middle deletion of session dequeue(&cur_task->sessions_to_be_handle);
has_middle_delete = true; continue;
break;
} }
userland_session_arr[session_idx] = (struct Session) { userland_session_arr[cur_userland_idx++] = (struct Session) {
.buf = (void*)server_session->buf_addr, .buf = (void*)server_session->buf_addr,
.capacity = server_session->capacity, .capacity = server_session->capacity,
.head = server_session->head, .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, .id = SERVER_SESSION_BACKEND(server_session)->session_id,
}; };
struct IpcMsg* msg = IPCSESSION_MSG(&userland_session_arr[session_idx]); enqueue(&cur_task->sessions_in_handle, 0, (void*)server_session);
if (msg != NULL && is_msg_needed(msg)) { dequeue(&cur_task->sessions_to_be_handle);
nr_sessions_need_to_handle++;
}
session_idx++;
} }
if (session_idx < arr_capacity) { // end of userland copy
userland_session_arr[session_idx].buf = NULL; if (cur_userland_idx < arr_capacity) {
if (!has_middle_delete && nr_sessions_need_to_handle == 0) { userland_session_arr[cur_userland_idx].buf = NULL;
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);
}
}
} }
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; return 0;
} }

View File

@ -35,8 +35,6 @@ Modification:
#include "syscall.h" #include "syscall.h"
#include "task.h" #include "task.h"
#define SERVER_DIR_NAME_SIZE 14
int sys_register_as_server(char* name) int sys_register_as_server(char* name)
{ {
// get server thread // get server thread

View File

@ -22,7 +22,7 @@
#include "syscall.h" #include "syscall.h"
#include "task.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) int sys_semaphore(sys_sem_option op, int param)
{ {
bool ret = false; bool ret = false;

View File

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

View File

@ -37,27 +37,5 @@ int sys_yield(task_yield_reason reason)
{ {
struct Thread* cur_task = cur_cpu()->task; struct Thread* cur_task = cur_cpu()->task;
xizi_task_manager.task_yield_noschedule(cur_task, false); 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; return 0;
} }

View File

@ -83,6 +83,9 @@ int syscall(int sys_num, uintptr_t param1, uintptr_t param2, uintptr_t param3, u
case SYSCALL_SLEEP: case SYSCALL_SLEEP:
ret = sys_sleep((intptr_t)param1); ret = sys_sleep((intptr_t)param1);
break; break;
case SYSCALL_WAIT_SESSION:
ret = sys_wait_session((struct Session*)param1);
break;
default: default:
ERROR("Unsurport syscall(%d) right now\n", sys_num); ERROR("Unsurport syscall(%d) right now\n", sys_num);
ret = -1; ret = -1;

View File

@ -62,10 +62,12 @@ struct MemSpace* alloc_memspace(char* name)
return NULL; return NULL;
} }
pmemspace->mem_usage.mem_block_root = NULL; rbtree_init(&pmemspace->kernspace_mem_usage.mem_block_map);
if (!CreateResourceTag(&pmemspace->mem_usage.tag, &pmemspace->tag, "MemUsage", TRACER_SYSOBJECT, (void*)&pmemspace->mem_usage)) { 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); DEBUG("Register MemUsage %s failed\n", name);
slab_free(&xizi_task_manager.memspace_allocator, (void*)pmemspace); slab_free(&xizi_task_manager.memspace_allocator, (void*)pmemspace);
DeleteResource(&pmemspace->tag, &xizi_task_manager.tag);
return NULL; return NULL;
} }
return pmemspace; return pmemspace;
@ -74,29 +76,26 @@ struct MemSpace* alloc_memspace(char* name)
void free_memspace(struct MemSpace* pmemspace) void free_memspace(struct MemSpace* pmemspace)
{ {
assert(pmemspace != NULL); assert(pmemspace != NULL);
assert(IS_DOUBLE_LIST_EMPTY(&pmemspace->thread_list_guard));
/* free page table and all its allocated memories */ /* free page table and all its allocated memories */
if (pmemspace->pgdir.pd_addr != NULL) { if (pmemspace->pgdir.pd_addr != NULL) {
xizi_pager.free_user_pgdir(&pmemspace->pgdir); 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 // 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) { while (rbt_node != NULL) {
assert((uintptr_t)V2P(rbt_node->key) >= PHY_MEM_BASE && (uintptr_t)V2P(rbt_node->key) < PHY_MEM_STOP); 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); kfree_by_ownership(pmemspace->kernspace_mem_usage.tag, (void*)rbt_node->key);
rbt_node = pmemspace->mem_usage.mem_block_root; 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 */ /* free ipc virt address allocator */

View File

@ -24,29 +24,28 @@
void semaphore_pool_init(struct XiziSemaphorePool* sem_pool) void semaphore_pool_init(struct XiziSemaphorePool* sem_pool)
{ {
assert(sem_pool != NULL); 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)); slab_init(&sem_pool->allocator, sizeof(struct ksemaphore));
doubleListNodeInit(&sem_pool->sem_list_guard); 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; RbtNode* target_sem_node = rbt_search(&sem_pool->sem_pool_map, sem_id);
DOUBLE_LIST_FOR_EACH_ENTRY(sem, &sem_pool->sem_list_guard, sem_list_node) if (target_sem_node == NULL) {
{ return NULL;
if (sem->id == sem_id) {
return sem;
}
} }
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); struct ksemaphore* sem = (struct ksemaphore*)slab_alloc(&sem_pool->allocator);
if (sem == NULL) { if (sem == NULL) {
ERROR("No memeory to alloc new semaphore.\n"); ERROR("No memeory to alloc new semaphore.\n");
return -1; return INVALID_SEM_ID;
} }
/* No error down here */ /* No error down here */
@ -55,19 +54,34 @@ int ksemaphore_alloc(struct XiziSemaphorePool* sem_pool, int val)
sem->id = sem_pool->next_sem_id++; sem->id = sem_pool->next_sem_id++;
if (UNLIKELY(sem->id == 0)) { if (UNLIKELY(sem->id == 0)) {
slab_free(&sem_pool->allocator, sem); slab_free(&sem_pool->allocator, sem);
return -1; return INVALID_SEM_ID;
} }
sem->val = val; sem->val = val;
doubleListNodeInit(&sem->sem_list_node); doubleListNodeInit(&sem->sem_list_node);
doubleListNodeInit(&sem->wait_list_guard); 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); doubleListAddOnHead(&sem->sem_list_node, &sem_pool->sem_list_guard);
sem_pool->nr_sem++;
return sem->id; 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 != NULL);
assert(thd->state == RUNNING); assert(thd->state == RUNNING);
@ -77,6 +91,7 @@ bool ksemaphore_wait(struct XiziSemaphorePool* sem_pool, struct Thread* thd, uin
if (sem == NULL) { if (sem == NULL) {
return false; 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 // no need to wait
if (sem->val > 0) { if (sem->val > 0) {
@ -91,7 +106,7 @@ bool ksemaphore_wait(struct XiziSemaphorePool* sem_pool, struct Thread* thd, uin
return true; 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 */ /* find sem */
struct ksemaphore* sem = ksemaphore_get_by_id(sem_pool, sem_id); 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); struct Thread* thd = CONTAINER_OF(sem->wait_list_guard.next, struct Thread, node);
assert(thd != NULL && thd->state == BLOCKED); assert(thd != NULL && thd->state == BLOCKED);
xizi_task_manager.task_unblock(thd); 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; 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 */ /* find sem */
struct ksemaphore* sem = ksemaphore_get_by_id(sem_pool, sem_id); 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); xizi_task_manager.task_unblock(thd);
} }
rbt_delete(&sem_pool->sem_pool_map, sem_id);
doubleListDel(&sem->sem_list_node); doubleListDel(&sem->sem_list_node);
slab_free(&sem_pool->allocator, sem); slab_free(&sem_pool->allocator, sem);
sem_pool->nr_sem--;
return true; return true;
} }

View File

@ -117,8 +117,10 @@ int _task_return_sys_resources(struct Thread* ptask)
assert(session_backend->server == ptask); assert(session_backend->server == ptask);
// cut the connection from task to session // cut the connection from task to session
server_session->closed = true; server_session->closed = true;
rbt_delete(&ptask->svr_sess_map, session_backend->session_id);
xizi_share_page_manager.delete_share_pages(session_backend); xizi_share_page_manager.delete_share_pages(session_backend);
} }
// close all client_sessions // close all client_sessions
struct client_session* client_session = NULL; struct client_session* client_session = NULL;
while (!IS_DOUBLE_LIST_EMPTY(&ptask->cli_sess_listhead)) { 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); assert(session_backend->client == ptask);
// cut the connection from task to session // cut the connection from task to session
client_session->closed = true; client_session->closed = true;
rbt_delete(&ptask->cli_sess_map, session_backend->session_id);
xizi_share_page_manager.delete_share_pages(session_backend); 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 */ // remove thread from used task list
if (task->thread_context.kern_stack_addr) { task_node_leave_list(task);
kfree_by_ownership(task->memspace->mem_usage.tag, (char*)task->thread_context.kern_stack_addr);
}
/* free memspace if needed to */ /* free memspace if needed to */
if (task->memspace != NULL) { 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 // awake deamon in this memspace
if (task->memspace->thread_to_notify != NULL) { if (task->memspace->thread_to_notify != NULL) {
if (task->memspace->thread_to_notify != task) { if (task->memspace->thread_to_notify != task) {
@ -195,6 +201,7 @@ static void _dealloc_task_cb(struct Thread* task)
} }
doubleListDel(&task->memspace_list_node); doubleListDel(&task->memspace_list_node);
/* free memspace if thread is the last one using it */ /* free memspace if thread is the last one using it */
if (IS_DOUBLE_LIST_EMPTY(&task->memspace->thread_list_guard)) { if (IS_DOUBLE_LIST_EMPTY(&task->memspace->thread_list_guard)) {
// free memspace // 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 // free task back to allocator
slab_free(&xizi_task_manager.task_allocator, (void*)task); 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 */ /* init basic task member */
doubleListNodeInit(&task->cli_sess_listhead); doubleListNodeInit(&task->cli_sess_listhead);
rbtree_init(&task->cli_sess_map);
doubleListNodeInit(&task->svr_sess_listhead); 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 */ /* 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 */ /* init main thread of task */
task->thread_context.task = task; task->thread_context.task = task;
// alloc stack page for 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 */ /* here inside, will no free memspace */
_dealloc_task_cb(task); _dealloc_task_cb(task);
return NULL; 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 */ /* from now on, _new_task_cb() will not generate error */
/* init vm */ /* init vm */
assert(pmemspace != NULL);
task->memspace = pmemspace;
task->thread_context.user_stack_idx = -1; task->thread_context.user_stack_idx = -1;
doubleListNodeInit(&task->memspace_list_node); doubleListNodeInit(&task->memspace_list_node);
doubleListAddOnBack(&task->memspace_list_node, &pmemspace->thread_list_guard); doubleListAddOnBack(&task->memspace_list_node, &pmemspace->thread_list_guard);

View File

@ -1,4 +1,4 @@
SRC_FILES := rbtree.c SRC_FILES := queue.c rbtree.c
include $(KERNEL_ROOT)/compiler.mk include $(KERNEL_ROOT)/compiler.mk

View File

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

View File

@ -1,387 +1,454 @@
#include <stddef.h>
#include "assert.h"
#include "rbtree.h" #include "rbtree.h"
#include "log.h"
#include "object_allocator.h"
struct RbtFactory { struct RbtFactory {
TraceTag tag; TraceTag tag;
struct slab_allocator queue_ele_allocator;
struct slab_allocator rbtnode_ele_allocator; struct slab_allocator rbtnode_ele_allocator;
}; };
struct Queue {
struct RbtNode* key;
struct Queue* next;
};
static struct RbtFactory rbt_factory; static struct RbtFactory rbt_factory;
void module_rbt_factory_init(TraceTag* _softkernel_tag) void module_rbt_factory_init(TraceTag* _softkernel_tag)
{ {
CreateResourceTag(&rbt_factory.tag, _softkernel_tag, "GlobalRbtFactory", TRACER_SYSOBJECT, &rbt_factory); 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)); slab_init(&rbt_factory.rbtnode_ele_allocator, sizeof(struct RbtNode));
} }
struct Queue* front = NULL; void delete_case1(RbtTree* tree, RbtNode* node);
struct Queue* rear = NULL; 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; if (node == NULL)
key = front->key; return BLACK;
return key;
}
int isempty()
{
if (front == NULL)
return 1;
else else
return 0; return node->color;
} }
void dequeue() static inline void set_color(enum rbt_type color, RbtNode* node)
{ {
if (isempty()) assert(node != NULL);
return; node->color = color;
struct Queue* temp = front;
front = front->next;
slab_free(&rbt_factory.queue_ele_allocator, (void*)temp);
} }
void enqueue(struct RbtNode* key) static inline RbtNode* get_parent(RbtNode* node)
{ {
struct Queue* temp = (struct Queue*)slab_alloc(&rbt_factory.queue_ele_allocator); assert(node != NULL);
temp->key = key; return node->parent;
temp->next = NULL;
if (front == NULL && rear == NULL) {
front = rear = temp;
return;
}
rear->next = temp;
rear = temp;
} }
void levelorder(struct RbtNode* root) static inline void set_parent(RbtNode* parent, RbtNode* node)
{ {
if (root == NULL) assert(node != NULL);
return; node->parent = parent;
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();
}
} }
void LeftRotate(struct RbtNode** T, struct RbtNode** x) static int is_root(RbtNode* node)
{ {
struct RbtNode* y = (*x)->right; assert(node != NULL);
(*x)->right = y->left; return (get_parent(node) == NULL);
}
if (y->left != NULL) static inline int is_black(RbtNode* node)
y->left->parent = *x; {
assert(node != NULL);
return (get_color(node) == BLACK);
}
y->parent = (*x)->parent; static inline int is_red(RbtNode* node)
{
if ((*x)->parent == NULL) assert(node != NULL);
*T = y; return (get_color(node) == RED);
}
else if (*x == (*x)->parent->left)
(*x)->parent->left = y;
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 else
(*x)->parent->right = y; return node->parent->left;
y->left = *x;
(*x)->parent = y;
} }
void RightRotate(struct RbtNode** T, struct RbtNode** x) static inline RbtNode* get_min(RbtNode* node)
{ {
struct RbtNode* y = (*x)->left; assert(node != NULL);
(*x)->left = y->right; while (node->left) {
node = node->left;
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;
}
}
} }
(*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); assert(node != NULL);
z->key = key; while (node->right) {
z->data = data; node = node->right;
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;
} }
z->parent = y; return node;
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;
} }
void preorder(struct RbtNode* root) RbtNode* rbtree_min(RbtTree* tree)
{ {
if (root == NULL) if (tree->root == NULL)
return; return NULL;
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));
}
else { else {
y = Tree_minimum(z->right); return get_min(tree->root);
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;
} }
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) if (tree->root == NULL)
return root; return NULL;
else {
return get_max(tree->root);
}
}
if (root->key > x) RbtNode* rbtree_prev(RbtNode* node)
return rbt_search(root->left, x); {
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 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;
} }