forked from xuos/xiuos
Valid 3 code version
This commit is contained in:
parent
7b6c93d391
commit
3e1479bdf0
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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; \
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ Modification:
|
|||
#include "libserial.h"
|
||||
|
||||
struct Session {
|
||||
int id;
|
||||
uintptr_t id;
|
||||
int capacity;
|
||||
int head;
|
||||
int tail;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
|
@ -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);
|
|
@ -32,12 +32,13 @@ Modification:
|
|||
#include <stdint.h>
|
||||
|
||||
#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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
|
||||
SRC_FILES := rbtree.c
|
||||
SRC_FILES := queue.c rbtree.c
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
|
|
|
@ -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++;
|
||||
}
|
|
@ -1,387 +1,454 @@
|
|||
|
||||
#include <stddef.h>
|
||||
|
||||
#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;
|
||||
}
|
Loading…
Reference in New Issue