Update XiZi_AIoT Kernel from tuyuyang

it is OK
This commit is contained in:
xuedongliang
2025-01-13 16:49:36 +08:00
512 changed files with 140610 additions and 1554 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
SRC_DIR := init memory trap task syscall
SRC_DIR := init memory trap task syscall tools
SRC_FILES := main.c load_apps.S
@@ -41,3 +41,5 @@ extern void panic(char*);
#define LIKELY(exp) __builtin_expect(exp, 1)
#define UNLIKELY(exp) __builtin_expect(exp, 0)
#define ERROR_FREE
@@ -46,22 +46,23 @@ static inline void bitmap64_init(struct bitmap64* bitmap)
static inline int bitmap64_alloc(struct bitmap64* bitmap)
{
int free_bit = -1;
// free bit is the first 0 bit, from [1, 64]
// free bit is the first 0 bit, from [0, 63]
free_bit = __builtin_ffsl(~(uint64_t)(bitmap->map));
// handle if bitmap is full (no using 64th bit here)
if (free_bit == 0) {
return -1;
}
assert(free_bit < 64 && free_bit >= 1);
free_bit -= 1;
assert(free_bit < 64 && free_bit >= 0);
// alloc and return
bitmap->map |= (1 << (free_bit - 1));
return free_bit - 1;
bitmap->map |= (1ULL << free_bit);
return free_bit;
}
static inline void bitmap64_free(struct bitmap64* bitmap, int idx)
{
// usages of bitmap64 must be correct
assert((bitmap->map & (1 << idx)) != 0);
assert((bitmap->map & (1ULL << idx)) != 0);
// free bit
bitmap->map &= ~(uint64_t)(1 << idx);
bitmap->map &= ~(uint64_t)(1ULL << idx);
}
@@ -31,13 +31,11 @@ Modification:
#include "list.h"
#include "memlayout.h"
#include "spinlock.h"
#include "pagetable.h"
#include <stdbool.h>
#include <stdint.h>
#define MAX_BUDDY_ORDER (10)
#define MAX_BUDDY_ORDER (18)
#define FREE_LIST_INDEX(order) \
(1 << order)
@@ -71,7 +69,6 @@ struct KFreeList {
struct KBuddy {
uintptr_t n_pages;
uintptr_t use_lock;
struct spinlock lock;
struct KFreeList free_list[MAX_BUDDY_ORDER];
struct KPage* first_page;
uintptr_t mem_start;
@@ -54,13 +54,20 @@ typedef struct {
struct IpcArgInfo {
uint16_t offset;
uint16_t len;
};
union {
uint16_t attr;
struct {
uint16_t null_ptr : 1;
uint16_t reserved : 15;
};
};
} __attribute__((packed));
/* [header, ipc_arg_buffer_len[], ipc_arg_buffer[]] */
struct IpcMsg {
ipc_msg_header header;
uintptr_t buf[];
};
} __attribute__((packed));
enum {
IPC_ARG_INFO_BASE_OFFSET = sizeof(ipc_msg_header),
};
@@ -29,14 +29,26 @@ Modification:
*************************************************/
#pragma once
#include "pagetable.h"
#include "actracer.h"
#include "rbtree.h"
struct MemUsage {
TraceTag tag;
RbtTree mem_block_map;
};
bool module_phymem_init();
char* kalloc(size_t size);
bool kfree(char* vaddr);
bool raw_kfree(char* paddr);
void* kalloc_by_ownership(TraceTag owner, uintptr_t size);
bool kfree_by_ownership(TraceTag owner, void* vaddr);
char* raw_alloc(size_t size);
bool raw_free(char* paddr);
void* raw_alloc_by_ownership(TraceTag owner, uintptr_t size);
bool raw_free_by_ownership(TraceTag owner, void* vaddr);
void show_phymem_info();
@@ -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,22 +38,27 @@ 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;
RbtTree wait_thd_tree;
/* list to manage semaphores */
/// @todo Use RB-Tree to manage all semaphores
struct double_list_node sem_list_node;
};
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);
+14 -1
View File
@@ -35,6 +35,8 @@ Modification:
#define OUTPUT_LEVLE_DEBUG 1
#define OUTPUT_LEVLE_ERROR 2
#define OUTPUT_LEVEL_TEST 3
#define OUTPUT_LEVLE OUTPUT_LEVLE_DEBUG
// #define OUTPUT_LEVLE OUTPUT_LEVLE_LOG
@@ -56,10 +58,21 @@ Modification:
#define DEBUG_PRINTF(f, args...)
#endif
#define DEBUG(f, args...) \
#if (OUTPUT_LEVLE >= OUTPUT_LEVLE_TEST)
#define RECORD_PRINTF(f, args...) \
KPrintf(f, ##args)
#else
#define RECORD_PRINTF(f, args...)
#endif
#define DEBUG(f, args...) \
DEBUG_PRINTF("DEBUG: [%s] ", __func__); \
DEBUG_PRINTF(f, ##args)
#define RECORD(f, args...) \
RECORD_PRINTF("DEBUG: [%s] ", __func__); \
RECORD_PRINTF(f, ##args)
#define ERROR(f, args...) \
KPrintf("ERROR: [%s %d] ", __func__, __LINE__); \
KPrintf(f, ##args)
@@ -27,8 +27,17 @@ Author: AIIT XUOS Lab
Modification:
1. first version
*************************************************/
#pragma once
#include "task.h"
#include "actracer.h"
#include "bitmap64.h"
#include "buddy.h"
#include "kalloc.h"
#include "list.h"
struct TopLevelPageDirectory {
uintptr_t* pd_addr;
};
struct ThreadStackPointer {
int argc;
@@ -37,7 +46,30 @@ struct ThreadStackPointer {
uintptr_t user_stack_vaddr;
};
struct MemSpace* alloc_memspace();
struct MemSpace {
/* trace node */
TraceTag tag;
/* mem usage info */
struct MemUsage kernspace_mem_usage;
struct MemUsage userspace_mem_usage;
struct MemUsage customized_mapping_mem_map;
/* task memory resources */
struct TopLevelPageDirectory pgdir; // [phy] vm pgtbl base address
uintptr_t heap_base; // mem size of proc used(allocated by kernel)
uintptr_t mem_size;
/* task communication mem resources */
struct KBuddy* massive_ipc_allocator;
/* thread using this memspace */
struct bitmap64 thread_stack_idx_bitmap;
struct double_list_node thread_list_guard;
// thread to notify when sub-thread exit
struct Thread* thread_to_notify;
};
struct MemSpace* alloc_memspace(char* name);
void free_memspace(struct MemSpace* pmemspace);
uintptr_t* load_memspace(struct MemSpace* pmemspace, char* img_start);
struct ThreadStackPointer load_user_stack(struct MemSpace* pmemspace, char** argv);
struct ThreadStackPointer load_user_stack(struct MemSpace* pmemspace, char** argv);
@@ -29,10 +29,12 @@ Modification:
*************************************************/
#pragma once
#include "actracer_tag.h"
#include <stddef.h>
#include <stdint.h>
struct slab_state {
TraceTag owner_tag;
struct slab_state *prev, *next;
uint64_t bitmap;
uintptr_t refcount;
@@ -45,9 +47,10 @@ struct slab_allocator {
size_t slabsize;
uint64_t bitmap_empty;
struct slab_state *partial, *empty, *full;
char* name;
};
void slab_init(struct slab_allocator*, size_t);
void slab_init(struct slab_allocator*, size_t, char* name);
void slab_destroy(const struct slab_allocator*);
void* slab_alloc(struct slab_allocator*);
@@ -33,11 +33,12 @@ Modification:
#include <string.h>
#include "memlayout.h"
#include "actracer.h"
#include "mmu.h"
#include "mmu_common.h"
#include "actracer.h"
#include "memspace.h"
// clang-format off
#define ALIGNUP(size, align) (((uintptr_t)(size) + (uintptr_t)(align) - 1) & ~((uintptr_t)(align) - 1))
#define ALIGNDOWN(size, align) ((uintptr_t)(size) & ~((uintptr_t)(align) - 1))
@@ -49,10 +50,6 @@ Modification:
#define TOPLEVLE_PAGEDIR_SIZE sizeof(uintptr_t) * NUM_TOPLEVEL_PDE
// clang-format on
struct TopLevelPageDirectory {
uintptr_t* pd_addr;
};
struct PagerRightGroup {
struct TraceTag mmu_driver_tag;
};
@@ -60,10 +57,10 @@ struct PagerRightGroup {
struct XiziPageManager {
bool (*new_pgdir)(struct TopLevelPageDirectory* pgdir);
void (*free_user_pgdir)(struct TopLevelPageDirectory* pgdir);
bool (*map_pages)(uintptr_t* pd_addr, uintptr_t vaddr, uintptr_t paddr, int len, bool is_dev);
bool (*map_pages)(struct MemSpace* pmemspace, uintptr_t vaddr, uintptr_t paddr, int len, bool is_dev);
bool (*unmap_pages)(uintptr_t* pd_addr, uintptr_t vaddr, int len);
uintptr_t (*resize_user_pgdir)(struct TopLevelPageDirectory* pgdir, uintptr_t old_size, uintptr_t new_size);
uintptr_t (*resize_user_pgdir)(struct MemSpace* pmemspace, uintptr_t old_size, uintptr_t new_size);
uintptr_t (*address_translate)(struct TopLevelPageDirectory* pgdir, uintptr_t vaddr);
uintptr_t (*cross_vspace_data_copy)(struct TopLevelPageDirectory* pgdir, uintptr_t cross_dest, uintptr_t src, uintptr_t len);
};
@@ -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);
bool dequeue(Queue* queue);
bool enqueue(Queue* queue, uintptr_t key, void* data);
void module_queue_factory_init(TraceTag* _softkernel_tag);
@@ -0,0 +1,50 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
#include "actracer.h"
#define RBTTREE_INSERT_SECC 0
#define RBTTREE_INSERT_FAILED -1
#define RBTTREE_INSERT_EXISTED -2
#define RBTTREE_DELETE_SUCC 0
#define RBTTREE_DELETE_FAILED -1
// CLRS
// Insertion and Deletion in a Red Black Tree
enum rbt_type {
RED,
BLACK
};
typedef struct RbtNode {
uintptr_t key;
void* data;
struct RbtNode* left;
struct RbtNode* right;
struct RbtNode* parent;
enum rbt_type color;
} RbtNode;
typedef struct RbtTree {
RbtNode* root;
int nr_ele;
} RbtTree;
// return if the traverse needs to continue
typedef bool(rbt_traverse_fn)(RbtNode* node, void* data);
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 rbt_traverse(RbtTree* tree, rbt_traverse_fn fn, void* data);
void module_rbt_factory_init(TraceTag* _softkernel_tag);
static inline bool rbt_is_empty(RbtTree* tree)
{
return tree->nr_ele == 0;
}
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file scheduler.h
* @brief scheduler algorithm declaration
* @version 3.0
* @author AIIT XUOS Lab
* @date 2023.08.25
*/
/*************************************************
File name: scheduler.h
Description: scheduler algorithm declaration
Others:
History:
1. Date: 2023-08-28
Author: AIIT XUOS Lab
Modification:
1. first version
*************************************************/
#pragma once
#include "task.h"
struct Thread* max_priority_runnable_task(void);
struct Thread* round_robin_runnable_task(uint32_t priority);
void recover_priority(void);
@@ -1,36 +1,61 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file scheduler.h
* @brief scheduler algorithm declaration
* @version 3.0
* @author AIIT XUOS Lab
* @date 2023.08.25
*/
/*************************************************
File name: scheduler.h
Description: scheduler algorithm declaration
Others:
History:
1. Date: 2023-08-28
Author: AIIT XUOS Lab
Modification:
1. first version
*************************************************/
#pragma once
#include "actracer.h"
#include "ksemaphore.h"
#include "rbtree.h"
#include "task.h"
#define TASK_MAX_PRIORITY 32
#define UNINIT_SNODE_ID 0
typedef uintptr_t snode_id_t;
struct Thread* max_priority_runnable_task(void);
struct Thread* round_robin_runnable_task(uint32_t priority);
void recover_priority(void);
enum ThreadState {
NEVER_RUN = 0,
INIT,
READY,
RUNNING,
DEAD,
BLOCKED,
SLEEPING,
NR_STATE,
// follow state is temp for kernel use
TRANS_WAKING,
};
typedef struct ScheduleContext {
intptr_t remain_tick;
uint64_t run_time;
intptr_t unblock_signals;
} ScheduleContext;
typedef struct TaskSleepContext {
int64_t remain_ms;
} TaskSleepContext;
struct ScheduleNode {
struct Thread* pthd;
snode_id_t snode_id;
enum ThreadState state;
Queue state_trans_signal_queue;
ScheduleContext sched_context;
TaskSleepContext sleep_context;
};
struct Scheduler {
TraceTag tag;
RbtTree snode_state_pool[NR_STATE];
RbtTree state_trans_ref_map;
struct XiziSemaphorePool semaphore_pool;
};
extern struct Scheduler g_scheduler;
bool init_schedule_node(struct ScheduleNode* snode, struct Thread* bind_thd);
void enqueue_task_trans_state(struct Thread* thd, enum ThreadState state);
#define THREAD_TRANS_STATE(thd, state) enqueue_task_trans_state(thd, state);
bool task_trans_sched_state(struct ScheduleNode* snode, RbtTree* from_pool, RbtTree* to_pool, enum ThreadState target_state);
void task_block(struct Thread* thd);
void task_dead(struct Thread* thd);
void task_into_ready(struct Thread* thd);
@@ -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;
};
@@ -90,3 +92,23 @@ struct XiziSharePageManager {
extern struct XiziSharePageManager xizi_share_page_manager;
int module_share_page_init(struct SharePageRightGroup* right_group);
static inline void client_close_session(struct Thread* thd, struct client_session* cli_sess)
{
assert(cli_sess != NULL);
struct session_backend* sess_backend = CLIENT_SESSION_BACKEND(cli_sess);
assert(sess_backend->client == thd);
assert(cli_sess->closed == false);
cli_sess->closed = true;
xizi_share_page_manager.delete_share_pages(sess_backend);
}
static inline void server_close_session(struct Thread* thd, struct server_session* svr_sess)
{
assert(svr_sess != NULL);
struct session_backend* sess_backend = SERVER_SESSION_BACKEND(svr_sess);
assert(sess_backend->server == thd);
assert(svr_sess->closed == false);
svr_sess->closed = true;
xizi_share_page_manager.delete_share_pages(sess_backend);
}
@@ -48,6 +48,9 @@ Modification:
#define SYSCALL_KILL 12 // kill the task by id
#define SYSCALL_SEMAPHORE 13 // semaphore related operations
#define SYSCALL_SLEEP 14 // sleep
#define SYSCALL_WAIT_SESSION 15
// clang-format on
#ifndef __ASSEMBLER__
@@ -64,6 +67,9 @@ typedef enum {
SYS_STATE_SHOW_TASKS,
SYS_STATE_SHOW_MEM_INFO,
SYS_STATE_SHOW_CPU_INFO,
SYS_STATE_GET_CURRENT_TICK,
SYS_STATE_GET_CURRENT_SECOND,
SYS_STATE_SHOW_ACTREE,
} sys_state_option;
typedef enum {
@@ -72,12 +78,25 @@ typedef enum {
SYS_TASK_YIELD_BLOCK_IPC = 0x2,
} task_yield_reason;
typedef enum {
SYS_MMAP_NORMAL = 0x0,
SYS_MMAP_CUSTOMIZE,
} sys_mmap_type;
typedef struct {
sys_mmap_type type;
uintptr_t attr;
bool is_dev;
} sys_mmap_info;
typedef union {
struct {
uintptr_t memblock_start;
uintptr_t memblock_end;
} memblock_info;
int priority;
uintptr_t current_tick;
uintptr_t current_second;
} sys_state_info;
typedef enum {
@@ -99,14 +118,17 @@ int sys_register_as_server(char* name);
int sys_connect_session(char* path, int capacity, struct Session* user_session);
int sys_poll_session(struct Session* userland_session_arr, int arr_capacity);
int sys_close_session(struct Thread* task, struct Session* session);
int sys_wait_session(struct Session* userland_session);
int sys_exec(char* img_start, char* name, char** argv);
int sys_state(sys_state_option option, sys_state_info* info);
int sys_mmap(uintptr_t vaddr, uintptr_t paddr, int len, int is_dev);
int sys_mmap(uintptr_t* vaddr, uintptr_t* paddr, int len, int is_dev);
int sys_mmap_v2(uintptr_t* vaddr, uintptr_t* paddr, int len, sys_mmap_info* info);
int sys_register_irq(int irq_num, int irq_opcode);
int sys_unbind_irq_all(struct Thread* task);
int sys_unbind_irq(struct Thread* task, int irq_num);
int sys_semaphore(sys_sem_option op, int sem_id);
int sys_sleep(intptr_t ms);
#endif
+35 -40
View File
@@ -31,41 +31,25 @@ Modification:
#include "core.h"
#include "bitmap64.h"
#include "buddy.h"
#include "ksemaphore.h"
#include "list.h"
#include "memspace.h"
#include "object_allocator.h"
#include "pagetable.h"
#include "queue.h"
#include "share_page.h"
#include "spinlock.h"
#include "scheduler.h"
#define TASK_CLOCK_TICK 50
#define TASK_MAX_PRIORITY 32
#define TASK_DEFAULT_PRIORITY 2
#define TASK_NAME_MAX_LEN 16
#define SLEEP_MONITOR_CORE 0
enum ProcState {
INIT = 0,
READY,
RUNNING,
DEAD,
BLOCKED,
NEVER_RUN,
};
struct MemSpace {
/* task memory resources */
struct TopLevelPageDirectory pgdir; // [phy] vm pgtbl base address
uintptr_t heap_base; // mem size of proc used(allocated by kernel)
uintptr_t mem_size;
/* task communication mem resources */
struct KBuddy* massive_ipc_allocator;
/* thread using this memspace */
struct bitmap64 thread_stack_idx_bitmap;
struct double_list_node thread_list_guard;
};
typedef int tid_t;
/* Thread Control Block */
struct ThreadContext {
@@ -105,15 +89,15 @@ struct Thread {
/* task communication resources */
struct double_list_node cli_sess_listhead;
struct double_list_node svr_sess_listhead;
bool current_ipc_handled;
RbtTree cli_sess_map;
RbtTree svr_sess_map;
Queue sessions_to_be_handle;
Queue sessions_in_handle;
struct TraceTag server_identifier;
bool advance_unblock; // @todo abandon
/* task schedule attributes */
struct double_list_node node;
enum ProcState state;
int priority; // priority
int remain_tick;
int maxium_tick;
struct ScheduleNode snode;
};
struct SchedulerRightGroup {
@@ -121,12 +105,34 @@ struct SchedulerRightGroup {
struct TraceTag mmu_driver_tag;
};
/* @todo task pool to maintain task lifetime and support fast task search */
struct GlobalTaskPool {
RbtTree thd_ref_map;
struct double_list_node thd_listing_head;
};
struct TaskScheduler {
};
struct TaskLifecycleOperations {
/* new a task control block, checkout #sys_spawn for usage */
struct Thread* (*new_thread)(struct MemSpace* pmemspace);
/* free a task control block, this calls #free_user_pgdir to free all vitual spaces */
void (*free_thread)(struct Thread*);
};
struct XiziTaskManager {
TraceTag tag;
/* thead schedule lists */
struct double_list_node task_list_head[TASK_MAX_PRIORITY]; /* list of task control blocks that are allocated */
struct double_list_node task_running_list_head;
struct double_list_node task_blocked_list_head;
struct double_list_node task_sleep_list_head;
struct XiziSemaphorePool semaphore_pool;
/* living task pool */
TraceTag task_pool_tag;
/* task lifecycle Ops */
TraceTag task_lifecycle_ops_tag;
/* mem allocator */
struct slab_allocator memspace_allocator;
@@ -136,13 +142,6 @@ struct XiziTaskManager {
/* init task manager */
void (*init)();
/* new a task control block, checkout #sys_spawn for usage */
struct Thread* (*new_task_cb)(struct MemSpace* pmemspace);
/* free a task control block, this calls #free_user_pgdir to free all vitual spaces */
void (*free_pcb)(struct Thread*);
/* init a task control block, set name, remain_tick, state, cwd, priority, etc. */
void (*task_set_default_schedule_attr)(struct Thread*);
/* use by task_scheduler, find next READY task, should be in locked */
struct Thread* (*next_runnable_task)(void);
/* function that's runing by kernel thread context, schedule use tasks */
@@ -151,9 +150,6 @@ struct XiziTaskManager {
/* handle task state */
/* call to yield current use task */
void (*task_yield_noschedule)(struct Thread* task, bool is_blocking);
/* block and unblock task */
void (*task_block)(struct double_list_node* head, struct Thread* task);
void (*task_unblock)(struct Thread* task);
/* set task priority */
void (*set_cur_task_priority)(int priority);
};
@@ -162,5 +158,4 @@ extern uint32_t ready_task_priority;
extern struct Thread* next_task_emergency;
extern struct XiziTaskManager xizi_task_manager;
int spawn_embedded_task(char* img_start, char* name, char** argv);
bool module_task_manager_init(void);
bool module_task_manager_init(TraceTag* softkernel_tag);
@@ -31,10 +31,14 @@ Modification:
#include "assert.h"
#include "log.h"
#include "rbtree.h"
#include "task.h"
bool softkernel_init(struct TraceTag* _hardkernel_tag, struct TraceTag* _softkernel_tag)
bool softkernel_init(TraceTag* _hardkernel_tag, struct TraceTag* _softkernel_tag)
{
module_rbt_factory_init(_softkernel_tag);
module_queue_factory_init(_softkernel_tag);
struct TraceTag server_identifier_owner;
CreateResourceTag(&server_identifier_owner, _softkernel_tag, "server-identifier", TRACER_OWNER, NULL);
@@ -48,7 +52,7 @@ bool softkernel_init(struct TraceTag* _hardkernel_tag, struct TraceTag* _softker
AchieveResourceTag(&intr_driver_tag, _hardkernel_tag, "intr-ac-resource");
load_kern_pgdir(&mmu_driver_tag, &intr_driver_tag); // enter kernel virtmem space
module_task_manager_init(); // init task
module_task_manager_init(_softkernel_tag); // init task
struct SharePageRightGroup sp_rights;
AchieveResourceTag(&sp_rights.dcache_driver_tag, _hardkernel_tag, "dcache-ac-resource");
+1 -1
View File
@@ -35,7 +35,7 @@ user_apps:
.section .rawdata_init
.globl initapp
initapp:
.incbin "../services/app/bin/init"
.incbin "../services/app/bin/shell"
.section .rawdata_memfs
.globl memfs
+16 -5
View File
@@ -42,14 +42,24 @@ extern uintptr_t _binary_init_start[], _binary_default_fs_start[];
extern int sys_spawn(char* img_start, char* name, char** argv);
static struct TraceTag hardkernel_tag, softkernel_tag;
static volatile int core_init_done = 0;
static volatile int core_para_init = 0;
static void main_sync_cores()
{
while (core_para_init != ((1 << NR_CPU) - 1))
;
return;
}
int main(void)
{
/* init tracer */
uint32_t cpu_id = cur_cpuid();
core_para_init |= (1 << cpu_id);
if (cpu_id == 0) {
/* init memory management first */
module_phymem_init(); // init buddy management system
/* init tracer system */
sys_tracer_init();
@@ -80,26 +90,27 @@ int main(void)
for (int i = 1; i < NR_CPU; i++) {
// start secondary cpus
while ((core_para_init & (1 << (i - 1))) == 0)
;
cpu_start_secondary(i);
}
/* start first task */
char* init_task_param[2] = { "/app/init", 0 };
sys_spawn((char*)_binary_init_start, "init", init_task_param);
char* init_task_param[2] = { "/app/shell", 0 };
sys_spawn((char*)_binary_init_start, "shell", init_task_param);
char* fs_server_task_param[2] = { "/app/fs_server", 0 };
sys_spawn((char*)_binary_default_fs_start, "memfs", fs_server_task_param);
}
/* start scheduler */
struct SchedulerRightGroup scheduler_rights;
assert(AchieveResourceTag(&scheduler_rights.mmu_driver_tag, &hardkernel_tag, "mmu-ac-resource"));
assert(AchieveResourceTag(&scheduler_rights.intr_driver_tag, &hardkernel_tag, "intr-ac-resource"));
core_init_done |= (1 << cpu_id);
LOG_PRINTF("CPU %d init done\n", cpu_id);
spinlock_unlock(&whole_kernel_lock);
// sync memory
__sync_synchronize();
main_sync_cores();
start_smp_cache_broadcast(cpu_id);
// enter kernel seriously
xizi_enter_kernel();
@@ -2,7 +2,7 @@
#include $(KERNEL_ROOT)/compiler.mk
ifneq ($(findstring $(BOARD), ok1028a-c), )
ifneq ($(findstring $(BOARD), 3568), )
SRC_FILES := kalloc.c pagetable.c pagetable_level3.c buddy.c object_allocator.c share_page.c
endif
ifneq ($(findstring $(BOARD), imx6q-sabrelite zynq7000-zc702), )
@@ -31,6 +31,7 @@ Modification:
#include "buddy.h"
#include "kalloc.h"
#include "log.h"
#include "pagetable.h"
static void _buddy_split_page(struct KPage* page, uintptr_t low_order, uintptr_t high_order, struct KFreeList* list)
{
@@ -166,7 +167,8 @@ bool KBuddyInit(struct KBuddy* pbuddy, uintptr_t mem_start, uintptr_t mem_end)
// total number of free pages
pbuddy->n_pages = (pbuddy->mem_end - (uintptr_t)pbuddy->mem_start) >> LEVEL4_PTE_SHIFT;
memset(pbuddy->pages, 0, pbuddy->n_pages);
memset(pbuddy->pages, 0, pbuddy->n_pages * sizeof(struct KPage));
// memset(pbuddy->pages, 0, pbuddy->n_pages);
// init each free page list from 2^0 to 2^8
for (; i < MAX_BUDDY_ORDER; i++) {
@@ -30,6 +30,9 @@ Modification:
#include "kalloc.h"
#include "assert.h"
#include "memlayout.h"
#include "pagetable.h"
#include "actracer.h"
#include "buddy.h"
@@ -43,12 +46,13 @@ bool module_phymem_init()
uintptr_t kern_freemem_end = PHY_USER_FREEMEM_BASE;
uintptr_t user_freemem_start = PHY_USER_FREEMEM_BASE;
uintptr_t user_freemem_end = PHY_MEM_STOP;
user_phy_freemem_buddy.pages = NULL;
KBuddySysInit(&kern_virtmem_buddy, kern_freemem_start, kern_freemem_end);
KBuddyInit(&user_phy_freemem_buddy, user_freemem_start, user_freemem_end);
return true;
}
char* kalloc(size_t size)
char* kalloc(uintptr_t size)
{
char* mem_alloc = KBuddyAlloc(&kern_virtmem_buddy, size);
if (mem_alloc == NULL) {
@@ -63,11 +67,42 @@ char* kalloc(size_t size)
return mem_alloc;
}
void* kalloc_by_ownership(TraceTag owner, uintptr_t size)
{
void* new_mem = kalloc(size);
if (NULL == new_mem) {
return NULL;
}
struct MemUsage* usage = GetSysObject(struct MemUsage, &owner);
if (0 != rbt_insert(&usage->mem_block_map, (uintptr_t)new_mem, NULL)) {
kfree(new_mem);
return NULL;
}
return new_mem;
}
bool kfree(char* vaddr)
{
return KBuddyFree(&kern_virtmem_buddy, V2P_WO(vaddr));
}
bool kfree_by_ownership(TraceTag owner, void* vaddr)
{
struct MemUsage* usage = GetSysObject(struct MemUsage, &owner);
// DEBUG("%p %p %p %p\n", usage, usage->mem_block_root, usage->tag, vaddr);
RbtNode* node = rbt_search(&usage->mem_block_map, (uintptr_t)vaddr);
assert(NULL != node);
assert(0 == rbt_delete(&usage->mem_block_map, node->key));
return kfree(vaddr);
}
bool raw_kfree(char* paddr)
{
return KBuddyFree(&kern_virtmem_buddy, paddr);
}
char* raw_alloc(size_t size)
{
char* mem_alloc = KBuddyAlloc(&user_phy_freemem_buddy, size);
@@ -77,11 +112,36 @@ char* raw_alloc(size_t size)
return mem_alloc;
}
void* raw_alloc_by_ownership(TraceTag owner, uintptr_t size)
{
void* new_mem = raw_alloc(size);
if (!new_mem) {
return NULL;
}
struct MemUsage* usage = GetSysObject(struct MemUsage, &owner);
if (0 != rbt_insert(&usage->mem_block_map, (uintptr_t)new_mem, NULL)) {
raw_free(new_mem);
return NULL;
}
return new_mem;
}
bool raw_free(char* paddr)
{
return KBuddyFree(&user_phy_freemem_buddy, paddr);
}
bool raw_free_by_ownership(TraceTag owner, void* vaddr)
{
struct MemUsage* usage = GetSysObject(struct MemUsage, &owner);
RbtNode* node = rbt_search(&usage->mem_block_map, (uintptr_t)vaddr);
assert(NULL != node);
assert(0 == rbt_delete(&usage->mem_block_map, node->key));
return raw_free(vaddr);
}
void show_phymem_info()
{
KFreePagesInfo(&user_phy_freemem_buddy);
@@ -32,6 +32,7 @@ Modification:
#include "assert.h"
#include "kalloc.h"
#include "object_allocator.h"
#include "pagetable.h"
#define BITMAP_BITS_EMPTY_FULL ((uint64_t)0)
#define BITMAP_FIRST_BIT ((uint64_t)1)
@@ -44,10 +45,10 @@ Modification:
#define LOWLEVEL_ALLOC(size) kalloc(size)
#define LOWLEVEL_FREE(ptr) kfree(ptr)
#define ARENA_SIZE_PER_INCREASE PAGE_SIZE
#define ARENA_SIZE_PER_INCREASE (2 * PAGE_SIZE)
#define MAX_NR_ELEMENT_PER_SLABPAGE 64
void slab_init(struct slab_allocator* const allocator, const size_t element_size)
void slab_init(struct slab_allocator* const allocator, const size_t element_size, char* name)
{
if (allocator == NULL) {
panic("init a NULL slab_allocator\n");
@@ -63,8 +64,11 @@ void slab_init(struct slab_allocator* const allocator, const size_t element_size
allocator->nr_elements = allocator->nr_elements > MAX_NR_ELEMENT_PER_SLABPAGE ? MAX_NR_ELEMENT_PER_SLABPAGE : allocator->nr_elements;
allocator->bitmap_empty = ~BITMAP_BITS_EMPTY_FULL >> (MAX_NR_ELEMENT_PER_SLABPAGE - allocator->nr_elements);
allocator->partial = allocator->empty = allocator->full = NULL;
if (name) {
allocator->name = name;
}
}
void* slab_alloc(struct slab_allocator* const allocator)
@@ -107,7 +111,7 @@ void* slab_alloc(struct slab_allocator* const allocator)
/* achieve slab from outer arena */
allocator->partial = (struct slab_state*)LOWLEVEL_ALLOC(allocator->slabsize);
if (UNLIKELY(allocator->partial == NULL)) {
ERROR("no enough memory\n");
ERROR("slab %s: no enough memory\n", allocator->name);
return allocator->partial = NULL;
}
allocator->partial->prev = allocator->partial->next = NULL;
@@ -51,7 +51,7 @@ static bool _new_pgdir(struct TopLevelPageDirectory* pgdir)
return true;
}
static bool _map_pages(uintptr_t* pgdir, uintptr_t vaddr, uintptr_t paddr, int len, uintptr_t attr)
static bool _map_pages(uintptr_t* pgdir, uintptr_t vaddr, uintptr_t paddr, intptr_t len, uintptr_t attr)
{
assert(len >= 0);
vaddr = ALIGNDOWN(vaddr, LEVEL4_PTE_SIZE);
@@ -61,12 +61,12 @@ static bool _map_pages(uintptr_t* pgdir, uintptr_t vaddr, uintptr_t paddr, int l
while (true) {
uintptr_t* pte = NULL;
if ((pte = _page_walk(pgdir, vaddr, true)) == NULL) {
ERROR("pte not found for vaddr %x.\n", vaddr);
ERROR("pte not found for vaddr %p.\n", vaddr);
return false;
}
if (UNLIKELY(*pte != 0)) {
ERROR("remapping: vaddr: %x | paddr: %x | pte: %x |\n", vaddr, paddr, *pte);
ERROR("remapping: vaddr: %p | paddr: %p | pte: %p |\n", vaddr, paddr, *pte);
return false;
}
@@ -93,12 +93,12 @@ static bool _unmap_pages(uintptr_t* pgdir, uintptr_t vaddr, int len)
while (true) {
uintptr_t* pte = NULL;
if ((pte = _page_walk(pgdir, vaddr, false)) == NULL) {
ERROR("pte not found for vaddr %x.\n", vaddr);
ERROR("pte not found for vaddr %p.\n", vaddr);
return false;
}
if (*pte == 0) {
ERROR("unmap a unmapped page, vaddr: %x, pte: %x\n", vaddr, *pte);
ERROR("unmap a unmapped page, vaddr: %p, pte: %p\n", vaddr, *pte);
return false;
}
@@ -122,7 +122,7 @@ static bool _unmap_pages(uintptr_t* pgdir, uintptr_t vaddr, int len)
/// @param len
/// @param is_dev
/// @return
static bool _map_user_pages(uintptr_t* pgdir, uintptr_t vaddr, uintptr_t paddr, int len, bool is_dev)
static bool _map_user_pages(struct MemSpace* pmemspace, uintptr_t vaddr, uintptr_t paddr, int len, bool is_dev)
{
if (len < 0) {
return false;
@@ -140,13 +140,27 @@ static bool _map_user_pages(uintptr_t* pgdir, uintptr_t vaddr, uintptr_t paddr,
_p_pgtbl_mmu_access->MmuUsrDevPteAttr(&mem_attr);
}
return _map_pages(pgdir, vaddr, paddr, len, mem_attr);
return _map_pages(pmemspace->pgdir.pd_addr, vaddr, paddr, (intptr_t)len, mem_attr);
}
bool _map_customizable_page(struct MemSpace* pmemspace, uintptr_t vaddr, uintptr_t paddr, int len, uintptr_t attr)
{
if (len < 0) {
return false;
}
if (UNLIKELY(vaddr >= USER_MEM_TOP)) {
ERROR("mapping kernel space.\n");
return false;
}
return _map_pages(pmemspace->pgdir.pd_addr, vaddr, paddr, (intptr_t)len, attr);
}
/// assume that a user pagedir is allocated from [0, size)
/// if new_size > old_size, allocate more space,
/// if old_size > new_size, free extra space, to avoid unnecessary alloc/free.
static uintptr_t _resize_user_pgdir(struct TopLevelPageDirectory* pgdir, uintptr_t old_size, uintptr_t new_size)
static uintptr_t _resize_user_pgdir(struct MemSpace* pmemspace, uintptr_t old_size, uintptr_t new_size)
{
if (UNLIKELY(new_size > USER_MEM_TOP)) {
ERROR("user size out of range.\n");
@@ -158,19 +172,17 @@ static uintptr_t _resize_user_pgdir(struct TopLevelPageDirectory* pgdir, uintptr
}
uintptr_t cur_size = ALIGNUP(old_size, PAGE_SIZE);
uintptr_t size_needed = ALIGNUP(new_size, PAGE_SIZE) - cur_size;
while (cur_size < new_size) {
char* new_page = kalloc(PAGE_SIZE);
if (new_page == NULL) {
ERROR("No memory\n");
return cur_size;
}
memset(new_page, 0, PAGE_SIZE);
if (!xizi_pager.map_pages(pgdir->pd_addr, cur_size, V2P(new_page), PAGE_SIZE, false)) {
return cur_size;
}
cur_size += PAGE_SIZE;
// char* new_page = kalloc(size_needed);
char* new_page = kalloc_by_ownership(pmemspace->kernspace_mem_usage.tag, size_needed);
if (new_page == NULL) {
ERROR("No memory\n");
return cur_size;
}
memset(new_page, 0, size_needed);
if (!xizi_pager.map_pages(pmemspace, cur_size, V2P(new_page), size_needed, false)) {
return cur_size;
}
return new_size;
@@ -269,7 +281,7 @@ void load_kern_pgdir(struct TraceTag* mmu_driver_tag, struct TraceTag* intr_driv
// kern mem
_map_pages((uintptr_t*)kern_pgdir.pd_addr, KERN_MEM_BASE, PHY_MEM_BASE, (PHY_MEM_STOP - PHY_MEM_BASE), kern_attr);
// dev mem
_map_pages((uintptr_t*)kern_pgdir.pd_addr, DEV_VRTMEM_BASE, DEV_PHYMEM_BASE, DEV_MEM_SZ, dev_attr);
_map_pages((uintptr_t*)kern_pgdir.pd_addr, DEV_VRTMEM_BASE, DEV_PHYMEM_BASE, DEV_MEM_SIZE, dev_attr);
_p_pgtbl_mmu_access->LoadPgdir((uintptr_t)V2P(kern_pgdir.pd_addr));
}
@@ -65,31 +65,12 @@ uintptr_t* _page_walk(uintptr_t* pgdir, uintptr_t vaddr, bool alloc)
void _free_user_pgdir(struct TopLevelPageDirectory* pgdir)
{
uintptr_t low_bound = kern_virtmem_buddy.mem_start, high_bound = kern_virtmem_buddy.mem_end;
uintptr_t user_low_bound = user_phy_freemem_buddy.mem_start, user_high_bound = user_phy_freemem_buddy.mem_end;
uintptr_t end_idx = USER_MEM_TOP >> LEVEL3_PDE_SHIFT;
for (uintptr_t level4_entry_idx = 0; level4_entry_idx < end_idx; level4_entry_idx++) {
// free each level4 page table
uintptr_t* pgtbl_paddr = (uintptr_t*)LEVEL4_PTE_ADDR(pgdir->pd_addr[level4_entry_idx]);
if (pgtbl_paddr != NULL) {
// free each page
for (uintptr_t page_entry_idx = 0; page_entry_idx < NUM_LEVEL4_PTE; page_entry_idx++) {
uintptr_t vaddr = (level4_entry_idx << LEVEL3_PDE_SHIFT) | (page_entry_idx << LEVEL4_PTE_SHIFT);
// get page paddr
uintptr_t* page_paddr = (uintptr_t*)ALIGNDOWN(((uintptr_t*)P2V(pgtbl_paddr))[page_entry_idx], PAGE_SIZE);
if (page_paddr != NULL) {
// IPC vaddr should not be addressed here.
assert(vaddr < USER_IPC_SPACE_BASE || vaddr >= USER_IPC_SPACE_TOP);
if (LIKELY((uintptr_t)page_paddr >= low_bound && (uintptr_t)page_paddr < high_bound)) {
kfree(P2V(page_paddr));
} else if (LIKELY((uintptr_t)page_paddr >= user_low_bound && (uintptr_t)page_paddr < user_high_bound)) {
raw_free((char*)page_paddr);
}
}
}
kfree(P2V(pgtbl_paddr));
}
}
@@ -48,7 +48,7 @@ uintptr_t* _page_walk(uintptr_t* pgdir, uintptr_t vaddr, bool alloc)
uintptr_t* l3_pde_vaddr;
if (*l2_pde_ptr != 0) {
uintptr_t l3_table_paddr = (*l2_pde_ptr) & ~pde_attr;
uintptr_t l3_table_paddr = ALIGNDOWN(*l2_pde_ptr, PAGE_SIZE);
l3_pde_vaddr = (uintptr_t*)P2V(l3_table_paddr);
} else {
if (!alloc || !(l3_pde_vaddr = (uintptr_t*)kalloc(sizeof(uintptr_t) * NUM_LEVEL3_PDE))) {
@@ -63,7 +63,7 @@ uintptr_t* _page_walk(uintptr_t* pgdir, uintptr_t vaddr, bool alloc)
uintptr_t* l4_pte_vaddr;
if (*l3_pde_ptr != 0) {
uintptr_t l4_table_paddr = (*l3_pde_ptr) & ~pde_attr;
uintptr_t l4_table_paddr = ALIGNDOWN(*l3_pde_ptr, PAGE_SIZE);
l4_pte_vaddr = (uintptr_t*)P2V(l4_table_paddr);
} else {
if (!alloc || !(l4_pte_vaddr = (uintptr_t*)kalloc(sizeof(uintptr_t) * NUM_LEVEL4_PTE))) {
@@ -83,8 +83,6 @@ void _free_user_pgdir(struct TopLevelPageDirectory* pgdir)
return;
}
uintptr_t low_bound = kern_virtmem_buddy.mem_start, high_bound = kern_virtmem_buddy.mem_end;
uintptr_t user_low_bound = user_phy_freemem_buddy.mem_start, user_high_bound = user_phy_freemem_buddy.mem_end;
uintptr_t end_idx = (USER_MEM_TOP >> LEVEL2_PDE_SHIFT) & (NUM_LEVEL2_PDE - 1);
for (uintptr_t l2_entry_idx = 0; l2_entry_idx < end_idx; l2_entry_idx++) {
@@ -95,23 +93,6 @@ void _free_user_pgdir(struct TopLevelPageDirectory* pgdir)
for (uintptr_t l3_entry_idx = 0; l3_entry_idx < NUM_LEVEL3_PDE; l3_entry_idx++) {
uintptr_t* l4_table_paddr = (uintptr_t*)LEVEL4_PTE_ADDR(l3_table_vaddr[l3_entry_idx]);
if (l4_table_paddr != NULL) {
uintptr_t* l4_table_vaddr = P2V(l4_table_paddr);
for (uintptr_t page_entry_idx = 0; page_entry_idx < NUM_LEVEL4_PTE; page_entry_idx++) {
uintptr_t vaddr = (l2_entry_idx << LEVEL2_PDE_SHIFT) | (l3_entry_idx << LEVEL3_PDE_SHIFT) | (page_entry_idx << LEVEL4_PTE_SHIFT);
// get page paddr
uintptr_t* page_paddr = (uintptr_t*)ALIGNDOWN((l4_table_vaddr)[page_entry_idx], PAGE_SIZE);
if (page_paddr != NULL) {
// Ensure the virtual address is not in the IPC address space
assert(vaddr < USER_IPC_SPACE_BASE || vaddr >= USER_IPC_SPACE_TOP);
if (LIKELY((uintptr_t)page_paddr >= low_bound && (uintptr_t)page_paddr < high_bound)) {
kfree(P2V(page_paddr));
} else if (LIKELY((uintptr_t)page_paddr >= user_low_bound && (uintptr_t)page_paddr < user_high_bound)) {
raw_free((char*)page_paddr);
}
}
}
kfree(P2V(l4_table_paddr));
}
}
@@ -44,7 +44,7 @@ static struct slab_allocator* SessionAllocator()
static bool init = false;
static struct slab_allocator session_slab;
if (!init) {
slab_init(&session_slab, sizeof(struct session_backend));
slab_init(&session_slab, sizeof(struct session_backend), "SessionAllocator");
}
return &session_slab;
}
@@ -111,7 +111,7 @@ static uintptr_t map_task_share_page(struct Thread* task, const uintptr_t paddr,
vaddr = alloc_share_page_addr(task, nr_pages * 2);
// time to use buddy
if (vaddr >= USER_IPC_USE_ALLOCATOR_WATERMARK) {
if (vaddr + (2 * nr_pages * PAGE_SIZE) >= USER_IPC_USE_ALLOCATOR_WATERMARK) {
task->memspace->massive_ipc_allocator = (struct KBuddy*)slab_alloc(&xizi_task_manager.task_buddy_allocator);
if (!task->memspace->massive_ipc_allocator) {
ERROR("Alloc task buddy failed.\n");
@@ -133,12 +133,12 @@ static uintptr_t map_task_share_page(struct Thread* task, const uintptr_t paddr,
}
// map first area
if (!xizi_pager.map_pages(task->memspace->pgdir.pd_addr, vaddr, paddr, nr_pages * PAGE_SIZE, false)) {
if (!xizi_pager.map_pages(task->memspace, vaddr, paddr, nr_pages * PAGE_SIZE, false)) {
return (uintptr_t)NULL;
}
// map second area
if (!xizi_pager.map_pages(task->memspace->pgdir.pd_addr, vaddr + (nr_pages * PAGE_SIZE), paddr, nr_pages * PAGE_SIZE, false)) {
if (!xizi_pager.map_pages(task->memspace, vaddr + (nr_pages * PAGE_SIZE), paddr, nr_pages * PAGE_SIZE, false)) {
xizi_pager.unmap_pages(task->memspace->pgdir.pd_addr, vaddr, nr_pages * PAGE_SIZE);
return (uintptr_t)NULL;
}
@@ -161,9 +161,9 @@ uintptr_t task_map_pages(struct Thread* task, const uintptr_t vaddr, const uintp
bool ret = false;
if (is_dev) {
ret = xizi_pager.map_pages(task->memspace->pgdir.pd_addr, vaddr, paddr, nr_pages * PAGE_SIZE, true);
ret = xizi_pager.map_pages(task->memspace, vaddr, paddr, nr_pages * PAGE_SIZE, true);
} else {
ret = xizi_pager.map_pages(task->memspace->pgdir.pd_addr, vaddr, paddr, nr_pages * PAGE_SIZE, false);
ret = xizi_pager.map_pages(task->memspace, vaddr, paddr, nr_pages * PAGE_SIZE, false);
}
if (!ret) {
@@ -207,11 +207,34 @@ void unmap_task_share_pages(struct Thread* task, const uintptr_t task_vaddr, con
static int next_session_id = 1;
struct session_backend* create_share_pages(struct Thread* client, struct Thread* server, const int capacity)
{
/* alloc session backend */
struct session_backend* session_backend = (struct session_backend*)slab_alloc(SessionAllocator());
if (UNLIKELY(session_backend == NULL)) {
return NULL;
}
session_backend->session_id = next_session_id++;
if (0 != rbt_insert(&client->cli_sess_map, session_backend->session_id, &session_backend->client_side)) {
DEBUG("Rbt of %s no memory\n", client->name);
slab_free(SessionAllocator(), session_backend);
return NULL;
}
if (0 != rbt_insert(&server->svr_sess_map, session_backend->session_id, &session_backend->server_side)) {
DEBUG("Rbt of %s no memory\n", server->name);
rbt_delete(&client->cli_sess_map, session_backend->session_id);
slab_free(SessionAllocator(), session_backend);
return NULL;
}
sem_id_t new_sem_id = ksemaphore_alloc(&xizi_task_manager.semaphore_pool, 0);
if (new_sem_id == INVALID_SEM_ID) {
ERROR("No memory to alloc sem\n");
slab_free(SessionAllocator(), session_backend);
return NULL;
}
session_backend->client_sem_to_wait = new_sem_id;
int true_capacity = ALIGNUP(capacity, PAGE_SIZE);
int nr_pages = true_capacity / PAGE_SIZE;
@@ -220,6 +243,7 @@ struct session_backend* create_share_pages(struct Thread* client, struct Thread*
if (UNLIKELY(kern_vaddr == (uintptr_t)NULL)) {
ERROR("No memory for session\n");
slab_free(SessionAllocator(), session_backend);
ksemaphore_free(&xizi_task_manager.semaphore_pool, new_sem_id);
return NULL;
}
@@ -229,6 +253,7 @@ struct session_backend* create_share_pages(struct Thread* client, struct Thread*
if (UNLIKELY(client_vaddr == (uintptr_t)NULL)) {
kfree((char*)kern_vaddr);
slab_free(SessionAllocator(), session_backend);
ksemaphore_free(&xizi_task_manager.semaphore_pool, new_sem_id);
return NULL;
}
@@ -238,11 +263,11 @@ struct session_backend* create_share_pages(struct Thread* client, struct Thread*
unmap_task_share_pages(client, client_vaddr, nr_pages);
kfree((char*)kern_vaddr);
slab_free(SessionAllocator(), session_backend);
ksemaphore_free(&xizi_task_manager.semaphore_pool, new_sem_id);
return NULL;
}
/* build session_backend */
session_backend->session_id = next_session_id++;
session_backend->buf_kernel_addr = kern_vaddr;
session_backend->nr_pages = nr_pages;
session_backend->client = client;
@@ -286,24 +311,39 @@ int delete_share_pages(struct session_backend* session_backend)
// close ssesion in server's perspective
if (session_backend->server_side.closed && session_backend->server != NULL) {
xizi_share_page_manager.unmap_task_share_pages(session_backend->server, session_backend->server_side.buf_addr, session_backend->nr_pages);
doubleListDel(&session_backend->server_side.node);
session_backend->server->memspace->mem_size -= session_backend->nr_pages * PAGE_SIZE;
session_backend->server = NULL;
ERROR_FREE
{
assert(0 == rbt_delete(&session_backend->server->svr_sess_map, session_backend->session_id));
doubleListDel(&session_backend->server_side.node);
session_backend->server->memspace->mem_size -= session_backend->nr_pages * PAGE_SIZE;
session_backend->server = NULL;
}
}
// close ssesion in client's perspective
if (session_backend->client_side.closed && session_backend->client != NULL) {
xizi_share_page_manager.unmap_task_share_pages(session_backend->client, session_backend->client_side.buf_addr, session_backend->nr_pages);
doubleListDel(&session_backend->client_side.node);
session_backend->client->memspace->mem_size -= session_backend->nr_pages * PAGE_SIZE;
session_backend->client = NULL;
ERROR_FREE
{
assert(0 == rbt_delete(&session_backend->client->cli_sess_map, session_backend->session_id));
doubleListDel(&session_backend->client_side.node);
session_backend->client->memspace->mem_size -= session_backend->nr_pages * PAGE_SIZE;
session_backend->client = NULL;
assert(ksemaphore_free(&xizi_task_manager.semaphore_pool, session_backend->client_sem_to_wait));
}
}
/* free seesion backend */
if (session_backend->server_side.closed && session_backend->client_side.closed) {
assert(session_backend->client == NULL && session_backend->server == NULL);
kfree((void*)session_backend->buf_kernel_addr);
slab_free(SessionAllocator(), (void*)session_backend);
ERROR_FREE
{
assert(session_backend->client == NULL && session_backend->server == NULL);
assert(kfree((void*)session_backend->buf_kernel_addr));
slab_free(SessionAllocator(), (void*)session_backend);
}
}
return 0;
@@ -1,6 +1,7 @@
SRC_FILES := syscall.c \
sys_spawn.c \
sys_thread.c \
sys_sleep.c \
sys_yield.c \
sys_register_as_server.c \
sys_connect_session.c \
@@ -11,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,48 @@ int sys_close_session(struct Thread* cur_task, struct Session* session)
return -1;
}
/* check if session is a client one or a server one */
struct session_backend* session_backend = NULL;
struct client_session* client_session = NULL;
DOUBLE_LIST_FOR_EACH_ENTRY(client_session, &cur_task->cli_sess_listhead, node)
{
if ((uintptr_t)session->buf == client_session->buf_addr) {
session_backend = CLIENT_SESSION_BACKEND(client_session);
assert(session_backend->client == cur_task);
assert(client_session->closed == false);
client_session->closed = true;
xizi_share_page_manager.delete_share_pages(session_backend);
break;
/* check if session is a client one or a server one */
RbtNode* client_session_node = rbt_search(&cur_task->cli_sess_map, session->id);
if (client_session_node != NULL) {
struct client_session* client_session = (struct client_session*)client_session_node->data;
if (CLIENT_SESSION_BACKEND(client_session)->session_id != session->id || //
client_session->buf_addr != (uintptr_t)session->buf) {
ERROR("Error closing session from %s: Invalid session\n", cur_task->name);
return -1;
}
/* close client session */
session_backend = CLIENT_SESSION_BACKEND(client_session);
assert(session_backend->client == cur_task);
assert(client_session->closed == false);
client_session->closed = true;
xizi_share_page_manager.delete_share_pages(session_backend);
struct Thread* server_to_info = session_backend->server;
if (!enqueue(&server_to_info->sessions_to_be_handle, 0, (void*)&session_backend->server_side)) {
// @todo fix memory leak
} else {
assert(!queue_is_empty(&server_to_info->sessions_to_be_handle));
THREAD_TRANS_STATE(server_to_info, TRANS_WAKING);
}
}
if (UNLIKELY(session_backend == NULL)) {
struct server_session* server_session = NULL;
DOUBLE_LIST_FOR_EACH_ENTRY(server_session, &cur_task->svr_sess_listhead, node)
{
if ((uintptr_t)session->buf == server_session->buf_addr) {
session_backend = SERVER_SESSION_BACKEND(server_session);
assert(session_backend->server == cur_task);
assert(server_session->closed == false);
server_session->closed = true;
xizi_share_page_manager.delete_share_pages(session_backend);
break;
}
RbtNode* server_session_node = rbt_search(&cur_task->svr_sess_map, session->id);
if (server_session_node != NULL) {
struct server_session* server_session = (struct server_session*)server_session_node->data;
if (SERVER_SESSION_BACKEND(server_session)->session_id != session->id || //
server_session->buf_addr != (uintptr_t)session->buf) {
ERROR("Error closing session from %s: Invalid session\n", cur_task->name);
return -1;
}
session_backend = SERVER_SESSION_BACKEND(server_session);
assert(session_backend->server == cur_task);
assert(server_session->closed == false);
server_session->closed = true;
xizi_share_page_manager.delete_share_pages(session_backend);
}
/* close this session */
@@ -40,11 +40,11 @@ int sys_exit(struct Thread* ptask)
{
assert(ptask != NULL);
ptask->dead = true;
// free that task straightly if it's a blocked task
if (ptask->state == BLOCKED) {
xizi_task_manager.free_pcb(ptask);
// awake the task if it's a blocked task
if (ptask->snode.state == BLOCKED || ptask->snode.state == SLEEPING) {
THREAD_TRANS_STATE(ptask, TRANS_WAKING);
}
// yield current task in case it wants to exit itself
xizi_task_manager.task_yield_noschedule(cur_cpu()->task, false);
THREAD_TRANS_STATE(cur_cpu()->task, READY);
return 0;
}
@@ -27,42 +27,37 @@ Author: AIIT XUOS Lab
Modification:
1. first version
*************************************************/
#include "task.h"
#include "trap_common.h"
#include "task.h"
static bool kill_succ;
extern int sys_exit(struct Thread* ptask);
static bool kill_task(RbtNode* node, void* id)
{
struct ScheduleNode* snode = (struct ScheduleNode*)node->data;
struct Thread* thd = snode->pthd;
tid_t target_id = *(tid_t*)id;
if (thd->tid == target_id) {
sys_exit(thd);
kill_succ = true;
return false;
}
return true;
}
extern int sys_exit(struct Thread* task);
int sys_kill(int id)
{
struct Thread* task = NULL;
// check if task is a running one
DOUBLE_LIST_FOR_EACH_ENTRY(task, &xizi_task_manager.task_running_list_head, node)
{
if (task->tid == id) {
sys_exit(task);
return 0;
}
kill_succ = false;
for (int pool_id = 0; pool_id < NR_STATE; pool_id++) {
rbt_traverse(&g_scheduler.snode_state_pool[pool_id], kill_task, (void*)&id);
}
// check if task is a blocking one
DOUBLE_LIST_FOR_EACH_ENTRY(task, &xizi_task_manager.task_blocked_list_head, node)
{
if (task->tid == id) {
sys_exit(task);
return 0;
}
if (kill_succ) {
return 0;
}
// check if task is a ready one
for (int prio = 0; prio < TASK_MAX_PRIORITY; prio++) {
DOUBLE_LIST_FOR_EACH_ENTRY(task, &xizi_task_manager.task_list_head[prio], node)
{
if (task->tid == id) {
sys_exit(task);
return 0;
}
}
}
return -1;
}
@@ -36,34 +36,126 @@ Modification:
#include "syscall.h"
#include "task.h"
int sys_mmap(uintptr_t vaddr, uintptr_t paddr, int len, int is_dev)
int sys_mmap(uintptr_t* vaddr, uintptr_t* paddr, int len, int is_dev)
{
struct Thread* cur_task = cur_cpu()->task;
assert(cur_task != NULL);
int true_len = ALIGNUP(len, PAGE_SIZE);
if (paddr != (uintptr_t)NULL) {
if (xizi_share_page_manager.task_map_pages(cur_task, vaddr, paddr, true_len / PAGE_SIZE, is_dev) == (uintptr_t)NULL) {
if (*paddr != (uintptr_t)NULL) {
if (*paddr >= PHY_MEM_BASE && *paddr < PHY_MEM_STOP && cur_task->tid > 1) {
ERROR("mapping invalid memory: 0x%p\n", *paddr);
return -1;
}
if (xizi_share_page_manager.task_map_pages(cur_task, *vaddr, *paddr, true_len / PAGE_SIZE, is_dev) == (uintptr_t)NULL) {
return -1;
}
} else {
int load_len = 0;
uintptr_t load_vaddr = vaddr;
while (load_len < true_len) {
char* paddr = raw_alloc(PAGE_SIZE);
if (paddr == NULL) {
return -1;
}
if (xizi_share_page_manager.task_map_pages(cur_task, load_vaddr, (uintptr_t)paddr, 1, false) == (uintptr_t)NULL) {
raw_free(paddr);
return -1;
}
load_vaddr += PAGE_SIZE;
load_len += PAGE_SIZE;
uintptr_t load_vaddr = *vaddr;
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_by_ownership(cur_task->memspace->userspace_mem_usage.tag, new_paddr);
return -1;
}
CreateResourceTag(NULL, &cur_task->memspace->tag, "USER_MEMORY", TRACER_MEM_SIGNATURE, new_paddr);
*paddr = (uintptr_t)new_paddr;
}
cur_task->memspace->mem_size += true_len;
return vaddr + true_len;
*vaddr = *vaddr + true_len;
return 0;
}
extern bool _map_customizable_page(struct MemSpace* pmemspace, uintptr_t vaddr, uintptr_t paddr, int len, uintptr_t attr);
int sys_mmap_v2(uintptr_t* vaddr, uintptr_t* paddr, int len, sys_mmap_info* info)
{
struct Thread* cur_task = cur_cpu()->task;
assert(cur_task != NULL);
if (vaddr == NULL) {
ERROR("Invalid vaddr from %s\n", cur_task->name);
}
int true_len = ALIGNUP(len, PAGE_SIZE);
sys_mmap_type type = info->type;
uintptr_t vaddr_to_map = *vaddr;
if (type == SYS_MMAP_CUSTOMIZE) {
if (paddr == NULL || *paddr == (uintptr_t)NULL || vaddr_to_map == (uintptr_t)NULL) {
ERROR("Customized mapping from %s must have vaddr(%p) and paddr(%p)\n", cur_task->name, vaddr, paddr);
return -1;
}
uintptr_t paddr_to_map = *paddr;
TraceTag mem_signature_tag;
if (!CreateResourceTag(&mem_signature_tag, &cur_task->memspace->tag, "CUSTOMIZED_MEMORY", TRACER_MEM_SIGNATURE, (void*)vaddr)) {
ERROR("Sign memory signature failed from %s\n", cur_task->name);
return -1;
}
if (!_map_customizable_page(cur_task->memspace, vaddr_to_map, paddr_to_map, len, info->attr)) {
ERROR("%s mapping page failed(Short of memory)\n", cur_task->name);
DeleteResource(&mem_signature_tag, &cur_task->memspace->tag);
return -1;
}
return 0;
}
if (type == SYS_MMAP_NORMAL) {
bool is_dev = info->is_dev;
if (*paddr != (uintptr_t)NULL) {
if (paddr == NULL || *paddr == (uintptr_t)NULL || vaddr_to_map == (uintptr_t)NULL) {
ERROR("Invalid mapping from %s\n", cur_task->name);
return -1;
}
uintptr_t paddr_to_map = *paddr;
if (paddr_to_map >= PHY_MEM_BASE && paddr_to_map < PHY_MEM_STOP && cur_task->tid > 2) {
ERROR("mapping invalid memory: 0x%p by %d\n", paddr_to_map, cur_task->tid);
return -1;
}
if (xizi_share_page_manager.task_map_pages(cur_task, vaddr_to_map, paddr_to_map, true_len / PAGE_SIZE, is_dev) == (uintptr_t)NULL) {
ERROR("%s mapping page failed(Short of memory)\n", cur_task->name);
return -1;
}
} else {
char* new_paddr = raw_alloc_by_ownership(cur_task->memspace->userspace_mem_usage.tag, true_len);
if (new_paddr == NULL) {
ERROR("Alloc dynamic memory failed\n");
return -1;
}
TraceTag mem_signature_tag;
if (!CreateResourceTag(&mem_signature_tag, &cur_task->memspace->tag, "USER_MEMORY", TRACER_MEM_SIGNATURE, new_paddr)) {
raw_free_by_ownership(cur_task->memspace->userspace_mem_usage.tag, new_paddr);
ERROR("Sign memory signature failed from %s\n", cur_task->name);
return -1;
}
if (xizi_share_page_manager.task_map_pages(cur_task, vaddr_to_map, (uintptr_t)new_paddr, true_len / PAGE_SIZE, false) == (uintptr_t)NULL) {
raw_free_by_ownership(cur_task->memspace->userspace_mem_usage.tag, new_paddr);
DeleteResource(&mem_signature_tag, &cur_task->memspace->tag);
return -1;
}
// assign new_paddr back to user
*paddr = (uintptr_t)new_paddr;
}
cur_task->memspace->mem_size += true_len;
*vaddr = *vaddr + true_len;
return 0;
}
return -1;
}
@@ -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,45 +43,40 @@ int sys_poll_session(struct Session* userland_session_arr, int arr_capacity)
return -1;
}
struct double_list_node* cur_node = NULL;
struct server_session* server_session = NULL;
/* update old sessions */
for (int i = 0; i < arr_capacity; i++) {
if (UNLIKELY(userland_session_arr[i].buf == NULL)) {
break;
int cur_userland_idx = 0;
while (!queue_is_empty(&cur_task->sessions_in_handle)) {
struct server_session* server_session = (struct server_session*)queue_front(&cur_task->sessions_in_handle)->data;
assert(server_session != NULL);
// wrong session info
if (userland_session_arr[cur_userland_idx].id != SERVER_SESSION_BACKEND(server_session)->session_id || //
(uintptr_t)userland_session_arr[cur_userland_idx].buf != server_session->buf_addr) {
ERROR("mismatched old session from %s, user buf: %x, server buf: %x\n", cur_task->name, userland_session_arr[cur_userland_idx].buf, server_session->buf_addr);
} else {
// update session_backend
ksemaphore_signal(&xizi_task_manager.semaphore_pool, SERVER_SESSION_BACKEND(server_session)->client_sem_to_wait);
server_session->head = userland_session_arr[cur_userland_idx].head;
server_session->tail = userland_session_arr[cur_userland_idx].tail;
userland_session_arr[cur_userland_idx].buf = NULL;
userland_session_arr[cur_userland_idx].id = -1;
}
cur_node = cur_task->svr_sess_listhead.next;
server_session = CONTAINER_OF(cur_node, struct server_session, node);
if (UNLIKELY(server_session->buf_addr != (uintptr_t)userland_session_arr[i].buf)) {
ERROR("mismatched old session addr, user buf: %x, server buf: %x\n", userland_session_arr[i].buf, server_session->buf_addr);
return -1;
}
// update session_backend
// if current session is handled
if (server_session->head != userland_session_arr[i].head) {
struct Thread* client = SERVER_SESSION_BACKEND(server_session)->client;
if (client->state == BLOCKED) {
xizi_task_manager.task_unblock(client);
} else {
client->current_ipc_handled = true;
}
}
server_session->head = userland_session_arr[i].head;
server_session->tail = userland_session_arr[i].tail;
doubleListDel(cur_node);
doubleListAddOnBack(cur_node, &cur_task->svr_sess_listhead);
assert(dequeue(&cur_task->sessions_in_handle));
cur_userland_idx++;
}
/* poll with new sessions */
int nr_sessions_need_to_handle = 0;
bool has_middle_delete = false;
int session_idx = 0;
DOUBLE_LIST_FOR_EACH_ENTRY(server_session, &cur_task->svr_sess_listhead, node)
{
if (session_idx >= arr_capacity) {
cur_userland_idx = 0;
while (!queue_is_empty(&cur_task->sessions_to_be_handle)) {
if (cur_userland_idx == arr_capacity) {
break;
}
struct server_session* server_session = (struct server_session*)queue_front(&cur_task->sessions_to_be_handle)->data;
assert(server_session != NULL);
if (SERVER_SESSION_BACKEND(server_session)->client_side.closed) {
// client had closed it, then server will close it too
struct session_backend* session_backend = SERVER_SESSION_BACKEND(server_session);
@@ -97,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,
@@ -110,20 +97,22 @@ 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 (is_msg_needed(msg)) {
nr_sessions_need_to_handle++;
}
session_idx++;
}
if (session_idx < arr_capacity) {
userland_session_arr[session_idx].buf = NULL;
if (!has_middle_delete && nr_sessions_need_to_handle == 0) {
xizi_task_manager.task_yield_noschedule(cur_task, false);
xizi_task_manager.task_block(&xizi_task_manager.task_blocked_list_head, cur_task);
if (!enqueue(&cur_task->sessions_in_handle, 0, (void*)server_session)) {
userland_session_arr[cur_userland_idx].buf = NULL;
userland_session_arr[cur_userland_idx].id = 0;
break;
}
assert(dequeue(&cur_task->sessions_to_be_handle));
cur_userland_idx++;
}
// 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)) {
THREAD_TRANS_STATE(cur_task, BLOCKED);
}
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
@@ -75,9 +75,8 @@ static void send_irq_to_user(int irq_num)
buf->header.done = 0;
buf->header.magic = IPC_MSG_MAGIC;
buf->header.valid = 1;
if (irq_forward_table[irq_num].handle_task->state == BLOCKED) {
xizi_task_manager.task_unblock(irq_forward_table[irq_num].handle_task);
if (enqueue(&irq_forward_table[irq_num].handle_task->sessions_to_be_handle, 0, (void*)&irq_forward_table[irq_num].p_kernel_session->server_side)) {
THREAD_TRANS_STATE(irq_forward_table[irq_num].handle_task, TRANS_WAKING);
}
/* add session head */
@@ -92,7 +91,7 @@ int user_irq_handler(int irq, void* tf, void* arg)
next_task_emergency = irq_forward_table[irq].handle_task;
if (cur_cpu()->task != NULL) {
xizi_task_manager.task_yield_noschedule(cur_cpu()->task, false);
THREAD_TRANS_STATE(cur_cpu()->task, READY);
}
}
return 0;
@@ -117,15 +116,18 @@ int sys_register_irq(int irq_num, int irq_opcode)
// init kerenl sender proxy
if (kernel_irq_proxy == NULL) {
/// @todo handle corner cases
struct MemSpace* pmemspace = alloc_memspace();
struct MemSpace* pmemspace = alloc_memspace("KernelIrqProxy");
if (pmemspace == NULL) {
return -1;
}
xizi_pager.new_pgdir(&pmemspace->pgdir);
memcpy(pmemspace->pgdir.pd_addr, kern_pgdir.pd_addr, TOPLEVLE_PAGEDIR_SIZE);
kernel_irq_proxy = xizi_task_manager.new_task_cb(pmemspace);
kernel_irq_proxy->state = NEVER_RUN;
struct TaskLifecycleOperations* tlo = GetSysObject(struct TaskLifecycleOperations, &xizi_task_manager.task_lifecycle_ops_tag);
kernel_irq_proxy = tlo->new_thread(pmemspace);
task_trans_sched_state(&kernel_irq_proxy->snode, //
&g_scheduler.snode_state_pool[INIT], //
&g_scheduler.snode_state_pool[NEVER_RUN], NEVER_RUN);
}
// bind irq to session
@@ -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,43 @@
/*
* 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_sleep.c
* @brief task sleep
* @version 3.0
* @author AIIT XUOS Lab
* @date 2023.08.25
*/
/*************************************************
File name: sys_sleep.c
Description:
Others:
History:
1. Date: 2023-08-28
Author: AIIT XUOS Lab
Modification:
1. first version
*************************************************/
#include "multicores.h"
#include "syscall.h"
#include "task.h"
#include "assert.h"
int sys_sleep(intptr_t ms)
{
struct Thread* cur_task = cur_cpu()->task;
cur_task->snode.sleep_context.remain_ms = ms;
THREAD_TRANS_STATE(cur_task, SLEEPING);
return 0;
}
@@ -38,7 +38,7 @@ extern int sys_new_thread(struct MemSpace* pmemspace, struct Thread* task, uintp
int sys_spawn(char* img_start, char* name, char** argv)
{
// alloc a new memspace
struct MemSpace* pmemspace = alloc_memspace();
struct MemSpace* pmemspace = alloc_memspace(name);
if (pmemspace == NULL) {
return -1;
}
@@ -52,10 +52,16 @@ int sys_spawn(char* img_start, char* name, char** argv)
}
// alloc a new pcb
struct Thread* new_task_cb = xizi_task_manager.new_task_cb(pmemspace);
struct TaskLifecycleOperations* tlo = GetSysObject(struct TaskLifecycleOperations, &xizi_task_manager.task_lifecycle_ops_tag);
struct Thread* new_task_cb = tlo->new_thread(pmemspace);
if (UNLIKELY(!new_task_cb)) {
ERROR("Unable to new task control block.\n");
free_memspace(pmemspace);
ERROR("Unable to new task control block %x.\n");
// error task allocation may free memspace before hand
// @todo use task ref map to handle this scene
if (NULL != pmemspace->tag.meta) {
free_memspace(pmemspace);
}
return -1;
}
assert(!IS_DOUBLE_LIST_EMPTY(&pmemspace->thread_list_guard));
@@ -30,6 +30,7 @@ Modification:
#include <stdint.h>
#include <string.h>
#include "actracer.h"
#include "assert.h"
#include "buddy.h"
#include "log.h"
@@ -41,65 +42,50 @@ Modification:
extern uint8_t _binary_fs_img_start[], _binary_fs_img_end[];
#define SHOWINFO_BORDER_LINE() LOG_PRINTF("******************************************************\n");
#define SHOWTASK_TASK_BASE_INFO(task) LOG_PRINTF(" %-6d %-16s %-4d 0x%x(%-d)\n", task->tid, task->name, task->priority, task->memspace->mem_size >> 10, task->memspace->mem_size >> 10)
#define SHOWTASK_TASK_BASE_INFO(task) LOG_PRINTF(" %-6d %-16s %-4d 0x%x(%-d)\n", task->tid, task->name, 0, task->memspace->mem_size >> 10, task->memspace->mem_size >> 10)
bool print_info(RbtNode* node, void* data)
{
struct ScheduleNode* snode = (struct ScheduleNode*)node->data;
struct Thread* thd = snode->pthd;
switch (snode->state) {
case INIT:
LOG_PRINTF("%-8s", "INIT");
break;
case READY:
LOG_PRINTF("%-8s", "READY");
break;
case RUNNING:
LOG_PRINTF("%-8s", "RUNNING");
break;
case DEAD:
LOG_PRINTF("%-8s", "DEAD");
break;
case BLOCKED:
LOG_PRINTF("%-8s", "BLOCK");
break;
case SLEEPING:
LOG_PRINTF("%-8s", "SLEEP");
break;
default:
break;
}
SHOWTASK_TASK_BASE_INFO(thd);
return true;
}
void show_tasks(void)
{
struct Thread* task = NULL;
SHOWINFO_BORDER_LINE();
for (int i = 0; i < NR_CPU; i++) {
LOG_PRINTF("CPU %-2d: %s\n", i, (global_cpus[i].task == NULL ? "NULL" : global_cpus[i].task->name));
}
SHOWINFO_BORDER_LINE();
LOG_PRINTF("%-8s %-6s %-16s %-4s %-8s\n", "STAT", "ID", "TASK", "PRI", "MEM(KB)");
DOUBLE_LIST_FOR_EACH_ENTRY(task, &xizi_task_manager.task_running_list_head, node)
{
LOG_PRINTF("%-8s", "RUNNING");
SHOWTASK_TASK_BASE_INFO(task);
}
for (int i = 0; i < TASK_MAX_PRIORITY; i++) {
if (IS_DOUBLE_LIST_EMPTY(&xizi_task_manager.task_list_head[i])) {
continue;
}
DOUBLE_LIST_FOR_EACH_ENTRY(task, &xizi_task_manager.task_list_head[i], node)
{
switch (task->state) {
case INIT:
LOG_PRINTF("%-8s", "INIT");
break;
case READY:
LOG_PRINTF("%-8s", "READY");
break;
case RUNNING:
LOG_PRINTF("%-8s", "RUNNING");
break;
case DEAD:
LOG_PRINTF("%-8s", "DEAD");
break;
default:
break;
}
SHOWTASK_TASK_BASE_INFO(task);
}
}
DOUBLE_LIST_FOR_EACH_ENTRY(task, &xizi_task_manager.task_blocked_list_head, node)
{
LOG_PRINTF("%-8s", "BLOCK");
SHOWTASK_TASK_BASE_INFO(task);
}
struct ksemaphore* sem = NULL;
DOUBLE_LIST_FOR_EACH_ENTRY(sem, &xizi_task_manager.semaphore_pool.sem_list_guard, sem_list_node)
{
task = NULL;
DOUBLE_LIST_FOR_EACH_ENTRY(task, &sem->wait_list_guard, node)
{
LOG_PRINTF("%-8s", "BLOCK");
SHOWTASK_TASK_BASE_INFO(task);
}
for (int pool_id = INIT; pool_id < NR_STATE; pool_id++) {
rbt_traverse(&g_scheduler.snode_state_pool[pool_id], print_info, NULL);
}
SHOWINFO_BORDER_LINE();
@@ -143,7 +129,7 @@ void show_cpu(void)
assert(current_task != NULL);
LOG_PRINTF(" ID COMMAND USED_TICKS FREE_TICKS \n");
LOG_PRINTF(" %d %s %d %d\n", cpu_id, current_task->name, TASK_CLOCK_TICK - current_task->remain_tick, current_task->remain_tick);
LOG_PRINTF(" %d %s %d %d\n", cpu_id, current_task->name, TASK_CLOCK_TICK - current_task->snode.sched_context.remain_tick, current_task->snode.sched_context.remain_tick);
LOG_PRINTF("***********************************************************\n");
return;
@@ -151,19 +137,43 @@ void show_cpu(void)
int sys_state(sys_state_option option, sys_state_info* info)
{
if (option == SYS_STATE_MEMBLOCK_INFO) {
switch (option) {
case SYS_STATE_MEMBLOCK_INFO: {
info->memblock_info.memblock_start = (uintptr_t)V2P(_binary_fs_img_start);
info->memblock_info.memblock_end = (uintptr_t)V2P(_binary_fs_img_end);
} else if (option == SYS_STATE_GET_HEAP_BASE) {
break;
}
case SYS_STATE_GET_HEAP_BASE:
return cur_cpu()->task->memspace->heap_base;
} else if (option == SYS_STATE_SET_TASK_PRIORITY) {
case SYS_STATE_SET_TASK_PRIORITY:
xizi_task_manager.set_cur_task_priority(info->priority);
} else if (option == SYS_STATE_SHOW_TASKS) {
break;
case SYS_STATE_SHOW_TASKS:
show_tasks();
} else if (option == SYS_STATE_SHOW_MEM_INFO) {
break;
case SYS_STATE_SHOW_MEM_INFO:
show_mem();
} else if (option == SYS_STATE_SHOW_CPU_INFO) {
break;
case SYS_STATE_SHOW_CPU_INFO:
show_cpu();
break;
case SYS_STATE_GET_CURRENT_TICK: {
extern void hw_current_tick(uintptr_t * tick);
hw_current_tick(&info->current_tick);
break;
}
case SYS_STATE_GET_CURRENT_SECOND: {
extern void hw_current_second(uintptr_t * tick);
hw_current_second(&info->current_second);
break;
}
case SYS_STATE_SHOW_ACTREE: {
debug_list_tracetree();
break;
}
case SYS_STATE_TEST:
default:
break;
}
return 0;
@@ -40,8 +40,9 @@ int sys_new_thread(struct MemSpace* pmemspace, struct Thread* task, uintptr_t en
struct ThreadStackPointer loaded_sp = load_user_stack(pmemspace, argv);
if (loaded_sp.stack_idx == -1) {
ERROR("Uable to load params to memspace.\n");
/* memspace is freed alone with free_pcb() */
xizi_task_manager.free_pcb(task);
/* memspace is freed alone with free_thread() */
struct TaskLifecycleOperations* tlo = GetSysObject(struct TaskLifecycleOperations, &xizi_task_manager.task_lifecycle_ops_tag);
tlo->free_thread(task);
return -1;
}
@@ -60,10 +61,15 @@ int sys_new_thread(struct MemSpace* pmemspace, struct Thread* task, uintptr_t en
last = name + 1;
}
}
strncpy(task->name, last, sizeof(task->name));
strncpy(task->name, last, sizeof(task->name) - 1);
// init pcb schedule attributes
xizi_task_manager.task_set_default_schedule_attr(task);
task_into_ready(task);
// thread init done by here
if (pmemspace->thread_to_notify == NULL) {
pmemspace->thread_to_notify = task;
}
return task->tid;
}
@@ -75,7 +81,8 @@ int sys_thread(uintptr_t entry, char* name, char** argv)
// use current task's memspace
struct MemSpace* pmemspace = cur_task->memspace;
struct Thread* task = xizi_task_manager.new_task_cb(pmemspace);
struct TaskLifecycleOperations* tlo = GetSysObject(struct TaskLifecycleOperations, &xizi_task_manager.task_lifecycle_ops_tag);
struct Thread* task = tlo->new_thread(pmemspace);
if (UNLIKELY(!task)) {
ERROR("Unable to new task control block.\n");
return -1;
@@ -0,0 +1,66 @@
/*
* 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;
if (!enqueue(&server_to_call->sessions_to_be_handle, 0, (void*)&session_backend->server_side)) {
sys_exit(cur_task);
return -1;
}
assert(!queue_is_empty(&server_to_call->sessions_to_be_handle));
ksemaphore_wait(&xizi_task_manager.semaphore_pool, cur_task, session_backend->client_sem_to_wait);
THREAD_TRANS_STATE(server_to_call, TRANS_WAKING);
return 0;
}
@@ -36,27 +36,6 @@ Modification:
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->current_ipc_handled) {
cur_task->current_ipc_handled = false;
} 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);
}
}
THREAD_TRANS_STATE(cur_task, READY);
return 0;
}
@@ -69,7 +69,7 @@ int syscall(int sys_num, uintptr_t param1, uintptr_t param2, uintptr_t param3, u
ret = sys_state(param1, (sys_state_info*)param2);
break;
case SYSCALL_MMAP:
ret = sys_mmap(param1, param2, (int)param3, (int)param4);
ret = sys_mmap_v2((uintptr_t*)param1, (uintptr_t*)param2, (int)param3, (sys_mmap_info*)param4);
break;
case SYSCALL_REGISTER_IRQ:
ret = sys_register_irq((int)param1, (int)param2);
@@ -80,6 +80,12 @@ int syscall(int sys_num, uintptr_t param1, uintptr_t param2, uintptr_t param3, u
case SYSCALL_SEMAPHORE:
ret = sys_semaphore((sys_sem_option)param1, (int)param2);
break;
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;
+50 -14
View File
@@ -32,16 +32,16 @@ Modification:
#include <stddef.h>
#include <stdint.h>
#include "assert.h"
#include "bitmap64.h"
#include "execelf.h"
#include "kalloc.h"
#include "memspace.h"
#include "pagetable.h"
#include "task.h"
#define MAX_SUPPORT_PARAMS 32
struct MemSpace* alloc_memspace()
struct MemSpace* alloc_memspace(char* name)
{
struct MemSpace* pmemspace = slab_alloc(&xizi_task_manager.memspace_allocator);
if (pmemspace == NULL) {
@@ -55,24 +55,61 @@ struct MemSpace* alloc_memspace()
pmemspace->heap_base = 0;
pmemspace->mem_size = 0;
pmemspace->pgdir.pd_addr = 0;
pmemspace->thread_to_notify = NULL;
if (!CreateResourceTag(&pmemspace->tag, &xizi_task_manager.tag, name, TRACER_OWNER, (void*)pmemspace)) {
DEBUG("Register MemSpace %s failed\n", name);
slab_free(&xizi_task_manager.memspace_allocator, (void*)pmemspace);
return NULL;
}
assert(pmemspace->tag.meta != NULL);
if (!CreateResourceTag(&pmemspace->kernspace_mem_usage.tag, &pmemspace->tag, "MemUsage", TRACER_SYSOBJECT, (void*)&pmemspace->kernspace_mem_usage) || //
!CreateResourceTag(&pmemspace->userspace_mem_usage.tag, &pmemspace->tag, "UserMemUsage", TRACER_SYSOBJECT, (void*)&pmemspace->userspace_mem_usage) || //
!CreateResourceTag(&pmemspace->customized_mapping_mem_map.tag, &pmemspace->tag, "CustomizaedMemMapping", TRACER_SYSOBJECT, (void*)&pmemspace->customized_mapping_mem_map)) {
DEBUG("Register MemUsage %s failed\n", name);
slab_free(&xizi_task_manager.memspace_allocator, (void*)pmemspace);
DeleteResource(&pmemspace->tag, &xizi_task_manager.tag);
return NULL;
}
rbtree_init(&pmemspace->kernspace_mem_usage.mem_block_map);
rbtree_init(&pmemspace->userspace_mem_usage.mem_block_map);
rbtree_init(&pmemspace->customized_mapping_mem_map.mem_block_map);
return pmemspace;
}
void free_memspace(struct MemSpace* pmemspace)
{
assert(pmemspace != NULL);
assert(IS_DOUBLE_LIST_EMPTY(&pmemspace->thread_list_guard));
/* free page table and all its allocated memories */
if (pmemspace->pgdir.pd_addr != NULL) {
xizi_pager.free_user_pgdir(&pmemspace->pgdir);
}
// delete space
RbtNode* rbt_node = pmemspace->kernspace_mem_usage.mem_block_map.root;
while (rbt_node != NULL) {
assert((uintptr_t)V2P(rbt_node->key) >= PHY_MEM_BASE && (uintptr_t)V2P(rbt_node->key) < PHY_MEM_STOP);
kfree_by_ownership(pmemspace->kernspace_mem_usage.tag, (void*)rbt_node->key);
rbt_node = pmemspace->kernspace_mem_usage.mem_block_map.root;
}
rbt_node = pmemspace->userspace_mem_usage.mem_block_map.root;
while (rbt_node != NULL) {
assert((uintptr_t)rbt_node->key >= PHY_MEM_BASE && (uintptr_t)rbt_node->key < PHY_MEM_STOP);
raw_free_by_ownership(pmemspace->userspace_mem_usage.tag, (void*)rbt_node->key);
rbt_node = pmemspace->userspace_mem_usage.mem_block_map.root;
}
/* free ipc virt address allocator */
if (pmemspace->massive_ipc_allocator != NULL) {
KBuddyDestory(pmemspace->massive_ipc_allocator);
slab_free(&xizi_task_manager.task_buddy_allocator, (void*)pmemspace->massive_ipc_allocator);
}
DeleteResource(&pmemspace->tag, &xizi_task_manager.tag);
slab_free(&xizi_task_manager.memspace_allocator, (void*)pmemspace);
}
@@ -100,14 +137,12 @@ uintptr_t* load_memspace(struct MemSpace* pmemspace, char* img_start)
/* allocate a pgdir */
/* only supports first inited memspace */
assert(pmemspace->pgdir.pd_addr == NULL);
struct TopLevelPageDirectory pgdir;
pgdir.pd_addr = NULL;
if (UNLIKELY(!xizi_pager.new_pgdir(&pgdir))) {
if (UNLIKELY(!xizi_pager.new_pgdir(&pmemspace->pgdir))) {
ERROR("Create new pgdir failed.\n");
goto error_exec;
}
/* copy kernel pagetable so that interrupt and syscall wont corrupt */
memcpy(pgdir.pd_addr, kern_pgdir.pd_addr, TOPLEVLE_PAGEDIR_SIZE);
memcpy(pmemspace->pgdir.pd_addr, kern_pgdir.pd_addr, TOPLEVLE_PAGEDIR_SIZE);
// read elf file by (header, section)
uintptr_t load_size = 0;
@@ -125,7 +160,7 @@ uintptr_t* load_memspace(struct MemSpace* pmemspace, char* img_start)
// read section
// 1. alloc space
if ((load_size = xizi_pager.resize_user_pgdir(&pgdir, load_size, ph.vaddr + ph.memsz))
if ((load_size = xizi_pager.resize_user_pgdir(pmemspace, load_size, ph.vaddr + ph.memsz))
!= ph.vaddr + ph.memsz) {
ERROR("Add uspace size failed.\n");
goto error_exec;
@@ -134,10 +169,11 @@ uintptr_t* load_memspace(struct MemSpace* pmemspace, char* img_start)
if (ph.vaddr % PAGE_SIZE != 0) {
LOG("Unsupported elf file, try use flag -N to compile.\n");
}
for (int addr_offset = 0; addr_offset < ph.filesz; addr_offset += PAGE_SIZE) {
uintptr_t page_paddr = xizi_pager.address_translate(&pgdir, ph.vaddr + addr_offset);
uintptr_t page_paddr = xizi_pager.address_translate(&pmemspace->pgdir, ph.vaddr + addr_offset);
if (page_paddr == 0) {
ERROR("copy elf file to unmapped addr: %x(pgdir: %x)\n", ph.vaddr + addr_offset, pgdir.pd_addr);
ERROR("copy elf file to unmapped addr: %x(pgdir: %x)\n", ph.vaddr + addr_offset, pmemspace->pgdir.pd_addr);
goto error_exec;
}
uintptr_t read_size = (ph.filesz - addr_offset < PAGE_SIZE ? ph.filesz - addr_offset : PAGE_SIZE);
@@ -147,15 +183,15 @@ uintptr_t* load_memspace(struct MemSpace* pmemspace, char* img_start)
/// elf file content now in memory
// memspace will use this page dir
pmemspace->pgdir = pgdir;
pmemspace->heap_base = ALIGNUP(load_size, PAGE_SIZE);
pmemspace->mem_size = pmemspace->heap_base;
return (uintptr_t*)elf.entry;
error_exec:
if (pgdir.pd_addr != NULL) {
xizi_pager.free_user_pgdir(&pgdir);
if (pmemspace->pgdir.pd_addr != NULL) {
xizi_pager.free_user_pgdir(&pmemspace->pgdir);
pmemspace->pgdir.pd_addr = NULL;
}
ERROR("Error loading memspace.\n");
return NULL;
@@ -208,7 +244,7 @@ struct ThreadStackPointer load_user_stack(struct MemSpace* pmemspace, char** arg
}
/* map memory to user stack space in memspace*/
if (!xizi_pager.map_pages(pmemspace->pgdir.pd_addr, USER_MEM_TOP - ((stack_idx + 1) * USER_STACK_SIZE), V2P(stack_bottom), USER_STACK_SIZE, false)) {
if (!xizi_pager.map_pages(pmemspace, USER_MEM_TOP - ((stack_idx + 1) * USER_STACK_SIZE), V2P(stack_bottom), USER_STACK_SIZE, false)) {
/* this could only fail due to inner page directory's allocation failure */
ERROR("User stack map failed\n");
handle_error_stack_loading(pmemspace, stack_idx, stack_bottom, false);
@@ -246,8 +282,8 @@ struct ThreadStackPointer load_user_stack(struct MemSpace* pmemspace, char** arg
pmemspace->mem_size += USER_STACK_SIZE;
loaded_sp.argc = argc;
loaded_sp.stack_idx = stack_idx;
loaded_sp.user_sp = user_vspace_sp;
loaded_sp.user_stack_vaddr = (uintptr_t)stack_bottom;
loaded_sp.stack_idx = stack_idx;
return loaded_sp;
}
+116 -51
View File
@@ -28,67 +28,132 @@ Modification:
1. first version
*************************************************/
#include "log.h"
#include "scheduler.h"
#include "multicores.h"
#include "schedule_algo.h"
static struct Thread* next_runable_task;
static uint64_t min_run_time;
#define MIN_RUN_TIME_BOUND 5
bool find_runable_task(RbtNode* node, void* data)
{
struct ScheduleNode* snode = (struct ScheduleNode*)node->data;
struct Thread* thd = snode->pthd;
if (!thd->dead) {
if (thd->snode.sched_context.run_time <= min_run_time) {
next_runable_task = thd;
min_run_time = thd->snode.sched_context.run_time;
thd->snode.sched_context.run_time++;
}
if (min_run_time <= MIN_RUN_TIME_BOUND) {
return false;
}
return true;
} else {
struct TaskLifecycleOperations* tlo = GetSysObject(struct TaskLifecycleOperations, &xizi_task_manager.task_lifecycle_ops_tag);
tlo->free_thread(thd);
return false;
}
return true;
}
struct Thread* max_priority_runnable_task(void)
{
static struct Thread* task = NULL;
static int priority = 0;
priority = __builtin_ffs(ready_task_priority) - 1;
if (priority > 31 || priority < 0) {
return NULL;
}
DOUBLE_LIST_FOR_EACH_ENTRY(task, &xizi_task_manager.task_list_head[priority], node)
{
assert(task != NULL);
if (task->state == READY && !task->dead) {
// found a runnable task, stop this look up
return task;
} else if (task->dead && task->state != RUNNING) {
xizi_task_manager.free_pcb(task);
return NULL;
}
}
return NULL;
/// @todo better strategy
next_runable_task = NULL;
min_run_time = UINT64_MAX;
rbt_traverse(&g_scheduler.snode_state_pool[READY], find_runable_task, NULL);
return next_runable_task;
}
struct Thread* round_robin_runnable_task(uint32_t priority)
#include "multicores.h"
#include "rbtree.h"
#include "task.h"
bool init_schedule_node(struct ScheduleNode* snode, struct Thread* bind_thd)
{
struct Thread* task = NULL;
snode->pthd = bind_thd;
snode->snode_id = bind_thd->tid;
DOUBLE_LIST_FOR_EACH_ENTRY(task, &xizi_task_manager.task_list_head[priority], node)
{
if (task->state == READY && !task->dead) {
// found a runnable task, stop this look up
return task;
} else if (task->dead && task->state != RUNNING) {
xizi_task_manager.free_pcb(task);
return NULL;
}
snode->sched_context.remain_tick = 0;
snode->sched_context.run_time = 0;
snode->sleep_context.remain_ms = 0;
snode->state = INIT;
if (RBTTREE_INSERT_SECC != rbt_insert(&g_scheduler.snode_state_pool[INIT], //
snode->snode_id, (void*)snode)) {
return false;
}
return NULL;
queue_init(&snode->state_trans_signal_queue);
return true;
}
/* recover task priority */
void recover_priority(void)
void enqueue_task_trans_state(struct Thread* thd, enum ThreadState state)
{
struct Thread* task = NULL;
for (int i = 1; i < TASK_MAX_PRIORITY; i++) {
if (i == TASK_DEFAULT_PRIORITY)
continue;
DOUBLE_LIST_FOR_EACH_ENTRY(task, &xizi_task_manager.task_list_head[i], node)
{
if (!IS_DOUBLE_LIST_EMPTY(&task->node)) {
// DEBUG("%s priority recover\n", task->name);
task->priority = TASK_DEFAULT_PRIORITY;
doubleListDel(&task->node);
doubleListAddOnBack(&task->node, &xizi_task_manager.task_list_head[task->priority]);
i--;
break;
}
}
/// @todo (current bug) handle memory drain
assert(enqueue(&thd->snode.state_trans_signal_queue, state, NULL));
int res = rbt_insert(&g_scheduler.state_trans_ref_map, thd->tid, (void*)thd);
assert(RBTTREE_INSERT_SECC == res || RBTTREE_INSERT_EXISTED == res);
}
bool task_trans_sched_state(struct ScheduleNode* snode, RbtTree* from_pool, RbtTree* to_pool, enum ThreadState target_state)
{
assert(snode != NULL);
assert(snode->snode_id != UNINIT_SNODE_ID && snode->pthd != NULL);
if (RBTTREE_DELETE_SUCC != rbt_delete(from_pool, snode->snode_id)) {
DEBUG("Thread %d not in from schedule pool\n", snode->pthd->tid);
return false;
}
if (RBTTREE_INSERT_SECC != rbt_insert(to_pool, snode->snode_id, (void*)snode)) {
DEBUG("Thread %d trans state failed\n", snode->pthd->tid);
return false;
}
snode->state = target_state;
return true;
}
void task_dead(struct Thread* thd)
{
assert(thd != NULL);
struct ScheduleNode* snode = &thd->snode;
assert(snode->state == INIT || snode->state == READY);
bool trans_res = task_trans_sched_state(snode, //
&g_scheduler.snode_state_pool[snode->state], //
&g_scheduler.snode_state_pool[DEAD], DEAD);
assert(trans_res = true);
assert(RBTTREE_DELETE_SUCC == rbt_delete(&g_scheduler.snode_state_pool[DEAD], snode->snode_id));
return;
}
void task_block(struct Thread* thd)
{
assert(thd != NULL);
struct ScheduleNode* snode = &thd->snode;
enum ThreadState thd_cur_state = snode->state;
bool trans_res = task_trans_sched_state(snode, //
&g_scheduler.snode_state_pool[thd_cur_state], //
&g_scheduler.snode_state_pool[BLOCKED], BLOCKED);
assert(trans_res = true);
return;
}
void task_into_ready(struct Thread* thd)
{
assert(thd != NULL);
struct ScheduleNode* snode = &thd->snode;
enum ThreadState thd_cur_state = snode->state;
bool trans_res = task_trans_sched_state(snode, //
&g_scheduler.snode_state_pool[thd_cur_state], //
&g_scheduler.snode_state_pool[READY], READY);
snode->sched_context.remain_tick = TASK_CLOCK_TICK;
assert(trans_res = true);
return;
}
@@ -24,29 +24,28 @@
void semaphore_pool_init(struct XiziSemaphorePool* sem_pool)
{
assert(sem_pool != NULL);
sem_pool->next_sem_id = 1;
slab_init(&sem_pool->allocator, sizeof(struct ksemaphore));
sem_pool->next_sem_id = INVALID_SEM_ID + 1;
slab_init(&sem_pool->allocator, sizeof(struct ksemaphore), "SemAllocator");
doubleListNodeInit(&sem_pool->sem_list_guard);
rbtree_init(&sem_pool->sem_pool_map);
sem_pool->nr_sem = 0;
}
static inline struct ksemaphore* ksemaphore_get_by_id(struct XiziSemaphorePool* sem_pool, int sem_id)
static inline struct ksemaphore* ksemaphore_get_by_id(struct XiziSemaphorePool* sem_pool, sem_id_t sem_id)
{
struct ksemaphore* sem = NULL;
DOUBLE_LIST_FOR_EACH_ENTRY(sem, &sem_pool->sem_list_guard, sem_list_node)
{
if (sem->id == sem_id) {
return sem;
}
RbtNode* target_sem_node = rbt_search(&sem_pool->sem_pool_map, sem_id);
if (target_sem_node == NULL) {
return NULL;
}
return NULL;
return (struct ksemaphore*)target_sem_node->data;
}
int ksemaphore_alloc(struct XiziSemaphorePool* sem_pool, int val)
sem_id_t ksemaphore_alloc(struct XiziSemaphorePool* sem_pool, sem_val_t val)
{
struct ksemaphore* sem = (struct ksemaphore*)slab_alloc(&sem_pool->allocator);
if (sem == NULL) {
ERROR("No memeory to alloc new semaphore.\n");
return -1;
return INVALID_SEM_ID;
}
/* No error down here */
@@ -55,28 +54,48 @@ 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);
rbtree_init(&sem->wait_thd_tree);
if (0 != rbt_insert(&sem_pool->sem_pool_map, sem->id, sem)) {
slab_free(&sem_pool->allocator, sem);
return INVALID_SEM_ID;
}
/* list sem to sem_pool */
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);
assert(thd->snode.state == RUNNING);
/* find sem */
struct ksemaphore* sem = ksemaphore_get_by_id(sem_pool, sem_id);
// invalid sem id
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) {
@@ -86,12 +105,13 @@ bool ksemaphore_wait(struct XiziSemaphorePool* sem_pool, struct Thread* thd, uin
// waiting at the sem
sem->val--;
xizi_task_manager.task_yield_noschedule(thd, false);
xizi_task_manager.task_block(&sem->wait_list_guard, thd);
THREAD_TRANS_STATE(thd, BLOCKED);
int rbt_insert_res = rbt_insert(&sem->wait_thd_tree, thd->tid, thd);
assert(RBTTREE_INSERT_SECC == rbt_insert_res || RBTTREE_INSERT_EXISTED == rbt_insert_res);
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);
@@ -100,19 +120,19 @@ bool ksemaphore_signal(struct XiziSemaphorePool* sem_pool, uint32_t sem_id)
return false;
}
if (sem->val < 0) {
if (!IS_DOUBLE_LIST_EMPTY(&sem->wait_list_guard)) {
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);
}
if (sem->val < 0 && !rbt_is_empty(&sem->wait_thd_tree)) {
assert(!rbt_is_empty(&sem->wait_thd_tree));
RbtNode* root = sem->wait_thd_tree.root;
struct Thread* thd = (struct Thread*)root->data;
rbt_delete(&sem->wait_thd_tree, root->key);
THREAD_TRANS_STATE(thd, TRANS_WAKING);
}
sem->val++;
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);
@@ -121,15 +141,25 @@ bool ksemaphore_free(struct XiziSemaphorePool* sem_pool, uint32_t sem_id)
return false;
}
struct Thread* thd = NULL;
DOUBLE_LIST_FOR_EACH_ENTRY(thd, &sem->wait_list_guard, node)
{
assert(thd != NULL);
xizi_task_manager.task_unblock(thd);
sem->val++;
return true;
}
bool ksemaphore_free(struct XiziSemaphorePool* sem_pool, sem_id_t sem_id)
{
/* find sem */
struct ksemaphore* sem = ksemaphore_get_by_id(sem_pool, sem_id);
// invalid sem id
if (sem == NULL) {
return false;
}
// by design: no waking any waiting threads
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;
}
+232 -194
View File
@@ -35,105 +35,97 @@ Modification:
#include "kalloc.h"
#include "memspace.h"
#include "multicores.h"
#include "scheduler.h"
#include "schedule_algo.h"
#include "syscall.h"
#include "task.h"
#include "trap_common.h"
struct CPU global_cpus[NR_CPU];
uint32_t ready_task_priority;
static inline void task_node_leave_list(struct Thread* task)
{
doubleListDel(&task->node);
if (IS_DOUBLE_LIST_EMPTY(&xizi_task_manager.task_list_head[task->priority])) {
ready_task_priority &= ~((uint32_t)1 << task->priority);
}
}
static inline void task_node_add_to_ready_list_head(struct Thread* task)
{
doubleListAddOnHead(&task->node, &xizi_task_manager.task_list_head[task->priority]);
ready_task_priority |= ((uint32_t)1 << task->priority);
}
static inline void task_node_add_to_ready_list_back(struct Thread* task)
{
doubleListAddOnBack(&task->node, &xizi_task_manager.task_list_head[task->priority]);
ready_task_priority |= ((uint32_t)1 << task->priority);
}
struct GlobalTaskPool global_task_pool;
struct Scheduler g_scheduler;
extern struct TaskLifecycleOperations task_lifecycle_ops;
static void _task_manager_init()
{
assert(CreateResourceTag(&xizi_task_manager.task_lifecycle_ops_tag, &xizi_task_manager.tag, //
"TaskLifeCycleOpTool", TRACER_SYSOBJECT, (void*)&task_lifecycle_ops));
// init task list to NULL
for (int i = 0; i < TASK_MAX_PRIORITY; i++) {
doubleListNodeInit(&xizi_task_manager.task_list_head[i]);
}
/* task scheduling list */
doubleListNodeInit(&xizi_task_manager.task_blocked_list_head);
doubleListNodeInit(&xizi_task_manager.task_running_list_head);
doubleListNodeInit(&xizi_task_manager.task_sleep_list_head);
// init task (slab) allocator
slab_init(&xizi_task_manager.memspace_allocator, sizeof(struct MemSpace));
slab_init(&xizi_task_manager.task_allocator, sizeof(struct Thread));
slab_init(&xizi_task_manager.task_buddy_allocator, sizeof(struct KBuddy));
slab_init(&xizi_task_manager.memspace_allocator, sizeof(struct MemSpace), "MemlpaceCtrlBlockAllocator");
slab_init(&xizi_task_manager.task_allocator, sizeof(struct Thread), "TreadCtrlBlockAllocator");
slab_init(&xizi_task_manager.task_buddy_allocator, sizeof(struct KBuddy), "DMBuddyAllocator");
/* global semaphore factory */
semaphore_pool_init(&xizi_task_manager.semaphore_pool);
/* task pool */
doubleListNodeInit(&global_task_pool.thd_listing_head);
rbtree_init(&global_task_pool.thd_ref_map);
// scheduler
assert(CreateResourceTag(&g_scheduler.tag, &xizi_task_manager.tag, //
"GlobalScheduler", TRACER_SYSOBJECT, (void*)&g_scheduler));
semaphore_pool_init(&g_scheduler.semaphore_pool);
for (int pool_id = 0; pool_id < NR_STATE; pool_id++) {
rbtree_init(&g_scheduler.snode_state_pool[pool_id]);
}
rbtree_init(&g_scheduler.state_trans_ref_map);
// tid pool
xizi_task_manager.next_pid = 0;
xizi_task_manager.next_pid = 1;
// init priority bit map
ready_task_priority = 0;
}
/// @brief alloc a new task without init
static struct Thread* _alloc_task_cb()
{
// alloc task and add it to used task list
struct Thread* task = (struct Thread*)slab_alloc(&xizi_task_manager.task_allocator);
if (UNLIKELY(task == NULL)) {
ERROR("Not enough memory\n");
return NULL;
}
// set tid once task is allocated
memset(task, 0, sizeof(*task));
task->tid = xizi_task_manager.next_pid++;
task->thread_context.user_stack_idx = -1;
return task;
}
int _task_return_sys_resources(struct Thread* ptask)
{
assert(ptask != NULL);
/* handle sessions for condition 1, ref. delete_share_pages() */
struct session_backend* session_backend = NULL;
// close all server_sessions
struct server_session* server_session = NULL;
while (!IS_DOUBLE_LIST_EMPTY(&ptask->svr_sess_listhead)) {
server_session = CONTAINER_OF(ptask->svr_sess_listhead.next, struct server_session, node);
assert(server_session != NULL);
session_backend = SERVER_SESSION_BACKEND(server_session);
assert(session_backend->server == ptask);
// cut the connection from task to session
server_session->closed = true;
xizi_share_page_manager.delete_share_pages(session_backend);
}
// close all client_sessions
struct client_session* client_session = NULL;
while (!IS_DOUBLE_LIST_EMPTY(&ptask->cli_sess_listhead)) {
client_session = CONTAINER_OF(ptask->cli_sess_listhead.next, struct client_session, node);
assert(client_session != NULL);
session_backend = CLIENT_SESSION_BACKEND(client_session);
assert(session_backend->client == ptask);
// cut the connection from task to session
client_session->closed = true;
xizi_share_page_manager.delete_share_pages(session_backend);
// RbtNode* sess_ref_node = ptask->svr_sess_map.root;
struct server_session* svr_session = CONTAINER_OF(ptask->svr_sess_listhead.next, struct server_session, node);
server_close_session(ptask, svr_session);
}
// close all client_sessions
while (!IS_DOUBLE_LIST_EMPTY(&ptask->cli_sess_listhead)) {
// RbtNode* sess_ref_node = ptask->cli_sess_map.root;
struct client_session* cli_session = CONTAINER_OF(ptask->cli_sess_listhead.next, struct client_session, node);
client_close_session(ptask, cli_session);
// info server that session is closed
struct session_backend* session_backend = CLIENT_SESSION_BACKEND(cli_session);
struct Thread* server_to_info = session_backend->server;
if (!enqueue(&server_to_info->sessions_to_be_handle, 0, (void*)&session_backend->server_side)) {
// @todo fix memory leak
} else {
assert(!queue_is_empty(&server_to_info->sessions_to_be_handle));
THREAD_TRANS_STATE(server_to_info, BLOCKED);
}
}
/* delete server identifier */
if (ptask->server_identifier.meta != NULL) {
// @todo figure out server-identifier ownership
struct TraceTag server_identifier_owner;
AchieveResourceTag(&server_identifier_owner, RequireRootTag(), "softkernel/server-identifier");
assert(server_identifier_owner.meta != NULL);
DeleteResource(&ptask->server_identifier, &server_identifier_owner);
assert(DeleteResource(&ptask->server_identifier, &server_identifier_owner));
}
// delete registered irq if there is one
@@ -144,9 +136,16 @@ int _task_return_sys_resources(struct Thread* ptask)
return 0;
}
extern void trap_return(void);
__attribute__((optimize("O0"))) void task_prepare_enter()
{
xizi_leave_kernel();
trap_return();
}
/// @brief this function changes task list without locking, so it must be called inside a lock critical area
/// @param task
static void _dealloc_task_cb(struct Thread* task)
static void _free_thread(struct Thread* task)
{
if (UNLIKELY(task == NULL)) {
ERROR("deallocating a NULL task\n");
@@ -172,14 +171,31 @@ static void _dealloc_task_cb(struct Thread* task)
}
}
/* free thread's kernel stack */
if (task->thread_context.kern_stack_addr) {
kfree((char*)task->thread_context.kern_stack_addr);
}
// remove thread from used task list
task_dead(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) {
if (task->memspace->thread_to_notify->snode.state == BLOCKED) {
THREAD_TRANS_STATE(task->memspace->thread_to_notify, TRANS_WAKING);
} else {
task->memspace->thread_to_notify->advance_unblock = true;
}
} else if (task->memspace->thread_to_notify == task) {
task->memspace->thread_to_notify = NULL;
}
}
doubleListDel(&task->memspace_list_node);
/* free memspace if thread is the last one using it */
if (IS_DOUBLE_LIST_EMPTY(&task->memspace->thread_list_guard)) {
// free memspace
@@ -187,85 +203,166 @@ 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);
}
/* alloc a new task with init */
extern void trap_return(void);
__attribute__((optimize("O0"))) void task_prepare_enter()
static struct Thread* _new_thread(struct MemSpace* pmemspace)
{
xizi_leave_kernel();
trap_return();
}
static struct Thread* _new_task_cb(struct MemSpace* pmemspace)
{
// alloc task space
struct Thread* task = _alloc_task_cb();
if (!task) {
return NULL;
}
/* init basic task member */
doubleListNodeInit(&task->cli_sess_listhead);
doubleListNodeInit(&task->svr_sess_listhead);
/* when creating a new task, memspace will be freed outside during memory shortage */
task->memspace = NULL;
/* init main thread of task */
task->thread_context.task = task;
// alloc stack page for task
if ((void*)(task->thread_context.kern_stack_addr = (uintptr_t)kalloc(USER_STACK_SIZE)) == NULL) {
/* here inside, will no free memspace */
_dealloc_task_cb(task);
return NULL;
}
/* 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);
/* set context of main thread stack */
/// stack bottom
memset((void*)task->thread_context.kern_stack_addr, 0x00, USER_STACK_SIZE);
char* sp = (char*)task->thread_context.kern_stack_addr + USER_STACK_SIZE - 4;
// alloc task space
struct Thread* task = (struct Thread*)slab_alloc(&xizi_task_manager.task_allocator);
if (task == NULL) {
ERROR("Not enough memory\n");
return NULL;
}
/// 1. trap frame into stack, for process to nomally return by trap_return
sp -= sizeof(*task->thread_context.trapframe);
task->thread_context.trapframe = (struct trapframe*)sp;
// [schedule related]
task->tid = xizi_task_manager.next_pid++;
if (!init_schedule_node(&task->snode, task)) {
ERROR("Not enough memory\n");
slab_free(&xizi_task_manager.task_allocator, (void*)task);
return NULL;
}
/// 2. context into stack
sp -= sizeof(*task->thread_context.context);
task->thread_context.context = (struct context*)sp;
arch_init_context(task->thread_context.context);
// alloc stack page for task
if ((void*)(task->thread_context.kern_stack_addr = (uintptr_t)kalloc_by_ownership(pmemspace->kernspace_mem_usage.tag, USER_STACK_SIZE)) == NULL) {
/* here inside, will no free memspace */
assert(RBTTREE_DELETE_SUCC == rbt_delete(&g_scheduler.snode_state_pool[INIT], task->snode.snode_id));
slab_free(&xizi_task_manager.task_allocator, (void*)task);
return NULL;
}
ERROR_FREE
{
/* init basic task ref member */
task->bind_irq = false;
/* vm & memory member */
task->thread_context.user_stack_idx = -1;
task->memspace = pmemspace;
doubleListNodeInit(&task->memspace_list_node);
doubleListAddOnBack(&task->memspace_list_node, &pmemspace->thread_list_guard);
/* thread context */
task->thread_context.task = task;
memset((void*)task->thread_context.kern_stack_addr, 0x00, USER_STACK_SIZE);
/// stack bottom
char* sp = (char*)task->thread_context.kern_stack_addr + USER_STACK_SIZE - 4;
/// 1. trap frame into stack, for process to nomally return by trap_return
/// trapframe (user context)
sp -= sizeof(*task->thread_context.trapframe);
task->thread_context.trapframe = (struct trapframe*)sp;
/// 2. context into stack
// (kernel context)
sp -= sizeof(*task->thread_context.context);
task->thread_context.context = (struct context*)sp;
arch_init_context(task->thread_context.context);
/* ipc member */
doubleListNodeInit(&task->cli_sess_listhead);
doubleListNodeInit(&task->svr_sess_listhead);
rbtree_init(&task->cli_sess_map);
rbtree_init(&task->svr_sess_map);
queue_init(&task->sessions_in_handle);
queue_init(&task->sessions_to_be_handle);
/// server identifier
task->server_identifier.meta = NULL;
}
// [name]
return task;
}
static void _task_set_default_schedule_attr(struct Thread* task)
{
task->remain_tick = TASK_CLOCK_TICK;
task->maxium_tick = TASK_CLOCK_TICK * 10;
task->state = READY;
task->priority = TASK_DEFAULT_PRIORITY;
task_node_add_to_ready_list_head(task);
}
struct TaskLifecycleOperations task_lifecycle_ops = {
.new_thread = _new_thread,
.free_thread = _free_thread,
};
static void task_state_set_running(struct Thread* task)
{
assert(task != NULL && task->state == READY);
task->state = RUNNING;
task_node_leave_list(task);
doubleListAddOnHead(&task->node, &xizi_task_manager.task_running_list_head);
assert(task != NULL && task->snode.state == READY);
assert(task_trans_sched_state(&task->snode, //
&g_scheduler.snode_state_pool[READY], //
&g_scheduler.snode_state_pool[RUNNING], RUNNING));
}
bool rbt_in_queue(RbtNode* node, void* data)
{
Queue* queue = (Queue*)data;
return enqueue(queue, node->key, node->data);
}
extern void show_tasks(void);
static void central_trans_task_state()
{
Queue tmp_queue;
queue_init(&tmp_queue);
rbt_traverse(&g_scheduler.state_trans_ref_map, rbt_in_queue, (void*)&tmp_queue);
while (!queue_is_empty(&tmp_queue)) {
struct Thread* thd = (struct Thread*)queue_front(&tmp_queue)->data;
struct ScheduleNode* snode = &thd->snode;
assert(cur_cpu()->task != NULL);
if (snode->state == RUNNING && cur_cpu()->task->tid != thd->tid) {
dequeue(&tmp_queue);
continue;
}
Queue* trans_queue = &snode->state_trans_signal_queue;
while (!queue_is_empty(trans_queue)) {
QueueNode* cur_qnode = queue_front(trans_queue);
enum ThreadState next_state = cur_qnode->key;
switch (next_state) {
case READY: {
if (snode->state == RUNNING || snode->state == READY) {
task_into_ready(thd);
} else {
ERROR("Thread %s(%d) Error trans to READY(from %d)\n", thd->name, thd->tid, snode->state);
}
break;
}
case BLOCKED: {
if (snode->sched_context.unblock_signals > 0) {
snode->sched_context.unblock_signals--;
task_into_ready(thd);
} else {
task_block(thd);
}
break;
}
case SLEEPING: {
/// @todo support sleep
break;
}
case TRANS_WAKING: {
if (snode->state == BLOCKED) {
task_into_ready(thd);
} else {
snode->sched_context.unblock_signals++;
task_into_ready(thd);
}
break;
}
case DEAD: {
/// @todo
break;
}
default:
break;
}
dequeue(trans_queue);
}
assert(RBTTREE_DELETE_SUCC == rbt_delete(&g_scheduler.state_trans_ref_map, thd->tid));
dequeue(&tmp_queue);
}
}
struct Thread* next_task_emergency = NULL;
@@ -280,7 +377,7 @@ static void _scheduler(struct SchedulerRightGroup right_group)
next_task = NULL;
/* find next runnable task */
assert(cur_cpu()->task == NULL);
if (next_task_emergency != NULL && next_task_emergency->state == READY) {
if (next_task_emergency != NULL && next_task_emergency->snode.state == READY) {
next_task = next_task_emergency;
} else {
next_task = xizi_task_manager.next_runnable_task();
@@ -290,99 +387,40 @@ static void _scheduler(struct SchedulerRightGroup right_group)
/* if there's not a runnable task, wait for one */
if (next_task == NULL) {
xizi_leave_kernel();
// there is no task to run, into low power mode
cpu_into_low_power();
/* leave kernel for other cores, so they may create a runnable task */
xizi_enter_kernel();
// activate cpu
cpu_leave_low_power();
continue;
}
/* run the chosen task */
// DEBUG_PRINTF("Thread %s(%d) to RUNNING\n", next_task->name, next_task->tid);
task_state_set_running(next_task);
cpu->task = next_task;
assert(next_task->memspace->pgdir.pd_addr != NULL);
p_mmu_driver->LoadPgdir((uintptr_t)V2P(next_task->memspace->pgdir.pd_addr));
context_switch(&cpu->scheduler, next_task->thread_context.context);
assert(next_task->state != RUNNING);
central_trans_task_state();
cpu->task = NULL;
}
}
static void _task_yield_noschedule(struct Thread* task, bool blocking)
{
assert(task != NULL);
/// @warning only support current task yield now
assert(task == cur_cpu()->task && task->state == RUNNING);
// rearrage current task position
task_node_leave_list(task);
if (task->state == RUNNING) {
task->state = READY;
}
task->remain_tick = TASK_CLOCK_TICK;
cur_cpu()->task = NULL;
task_node_add_to_ready_list_back(task);
}
static void _task_block(struct double_list_node* head, struct Thread* task)
{
assert(head != NULL);
assert(task != NULL);
assert(task->state != RUNNING);
task_node_leave_list(task);
task->state = BLOCKED;
doubleListAddOnHead(&task->node, head);
}
static void _task_unblock(struct Thread* task)
{
assert(task != NULL);
assert(task->state == BLOCKED);
task_node_leave_list(task);
task->state = READY;
task_node_add_to_ready_list_head(task);
}
/// @brief @warning not tested function
/// @param priority
static void _set_cur_task_priority(int priority)
{
if (priority < 0 || priority >= TASK_MAX_PRIORITY) {
ERROR("priority is invalid\n");
return;
}
struct Thread* current_task = cur_cpu()->task;
assert(current_task != NULL && current_task->state == RUNNING);
task_node_leave_list(current_task);
current_task->priority = priority;
task_node_add_to_ready_list_back(current_task);
return;
}
struct XiziTaskManager xizi_task_manager = {
.init = _task_manager_init,
.new_task_cb = _new_task_cb,
.free_pcb = _dealloc_task_cb,
.task_set_default_schedule_attr = _task_set_default_schedule_attr,
.next_runnable_task = max_priority_runnable_task,
.task_scheduler = _scheduler,
.task_block = _task_block,
.task_unblock = _task_unblock,
.task_yield_noschedule = _task_yield_noschedule,
.set_cur_task_priority = _set_cur_task_priority
};
bool module_task_manager_init(void)
bool module_task_manager_init(TraceTag* softkernel_tag)
{
CreateResourceTag(&xizi_task_manager.tag, softkernel_tag, "KTaskManager", TRACER_OWNER, &xizi_task_manager);
xizi_task_manager.init();
return true;
}
@@ -0,0 +1,4 @@
SRC_FILES := queue.c rbtree.c
include $(KERNEL_ROOT)/compiler.mk
@@ -0,0 +1,79 @@
#include "actracer.h"
#include "assert.h"
#include "queue.h"
struct QueueFactory {
TraceTag tag;
struct slab_allocator queue_ele_allocator;
};
static struct QueueFactory queue_factory;
void module_queue_factory_init(TraceTag* _softkernel_tag)
{
CreateResourceTag(&queue_factory.tag, _softkernel_tag, "GlobalQueueFactory", TRACER_SYSOBJECT, &queue_factory);
slab_init(&queue_factory.queue_ele_allocator, sizeof(struct QueueNode), "QueueNodeAllocator");
}
void queue_init(Queue* queue)
{
queue->front = NULL;
queue->rear = NULL;
queue->nr_ele = 0;
}
struct QueueNode* queue_front(Queue* queue)
{
return queue->front;
}
bool queue_is_empty(Queue* queue)
{
if (queue->front == NULL) {
assert(queue->nr_ele == 0);
return true;
}
return false;
}
bool dequeue(Queue* queue)
{
struct QueueNode* temp = queue->front;
if (queue->front == NULL) {
return false;
}
if (queue->front == queue->rear)
queue->front = queue->rear = NULL;
else
queue->front = queue->front->next;
queue->nr_ele--;
slab_free(&queue_factory.queue_ele_allocator, (void*)temp);
return true;
}
bool enqueue(Queue* queue, uintptr_t key, void* data)
{
QueueNode* temp = (struct QueueNode*)slab_alloc(&queue_factory.queue_ele_allocator);
if (temp == NULL) {
return false;
}
temp->key = key;
temp->data = data;
temp->next = NULL;
if (queue->front == NULL && queue->rear == NULL) {
queue->front = queue->rear = temp;
} else {
queue->rear->next = temp;
queue->rear = temp;
}
queue->nr_ele++;
return true;
}
@@ -0,0 +1,484 @@
#include <stddef.h>
#include "assert.h"
#include "rbtree.h"
struct RbtFactory {
TraceTag tag;
struct slab_allocator rbtnode_ele_allocator;
};
static struct RbtFactory rbt_factory;
void module_rbt_factory_init(TraceTag* _softkernel_tag)
{
CreateResourceTag(&rbt_factory.tag, _softkernel_tag, "GlobalRbtFactory", TRACER_SYSOBJECT, &rbt_factory);
slab_init(&rbt_factory.rbtnode_ele_allocator, sizeof(struct RbtNode), "RbtNodeAllocator");
}
void delete_case1(RbtTree* tree, RbtNode* node);
void delete_case2(RbtTree* tree, RbtNode* node);
void delete_case3(RbtTree* tree, RbtNode* node);
void delete_case4(RbtTree* tree, RbtNode* node);
void delete_case5(RbtTree* tree, RbtNode* node);
void delete_case6(RbtTree* tree, RbtNode* node);
static inline enum rbt_type get_color(RbtNode* node)
{
if (node == NULL)
return BLACK;
else
return node->color;
}
static inline void set_color(enum rbt_type color, RbtNode* node)
{
assert(node != NULL);
node->color = color;
}
static inline RbtNode* get_parent(RbtNode* node)
{
assert(node != NULL);
return node->parent;
}
static inline void set_parent(RbtNode* parent, RbtNode* node)
{
assert(node != NULL);
node->parent = parent;
}
static int is_root(RbtNode* node)
{
assert(node != NULL);
return (get_parent(node) == NULL);
}
static inline int is_black(RbtNode* node)
{
assert(node != NULL);
return (get_color(node) == BLACK);
}
static inline int is_red(RbtNode* node)
{
assert(node != NULL);
return (get_color(node) == RED);
}
RbtNode* sibling(RbtNode* node)
{
assert(node != NULL);
assert(node->parent != NULL); /* Root node has no sibling */
if (node == node->parent->left)
return node->parent->right;
else
return node->parent->left;
}
static inline RbtNode* get_min(RbtNode* node)
{
assert(node != NULL);
while (node->left) {
node = node->left;
}
return node;
}
static inline RbtNode* get_max(RbtNode* node)
{
assert(node != NULL);
while (node->right) {
node = node->right;
}
return node;
}
RbtNode* rbtree_min(RbtTree* tree)
{
if (tree->root == NULL)
return NULL;
else {
return get_min(tree->root);
}
}
RbtNode* rbtree_max(RbtTree* tree)
{
if (tree->root == NULL)
return NULL;
else {
return get_max(tree->root);
}
}
RbtNode* rbtree_prev(RbtNode* node)
{
assert(node != NULL);
if (node->left) {
return get_max(node->left);
} else {
RbtNode* parent;
while ((parent = get_parent(node)) && parent->left == node) {
node = parent;
}
return parent;
}
}
RbtNode* rbtree_next(RbtNode* node)
{
assert(node != NULL);
if (node->right)
return get_min(node->right);
else {
RbtNode* parent = NULL;
while ((parent = get_parent(node)) != NULL && parent->right == node) {
node = parent;
}
return parent;
}
}
RbtNode* rbtree_createnode(uintptr_t key, void* data)
{
RbtNode* newnode = slab_alloc(&rbt_factory.rbtnode_ele_allocator);
if (newnode == NULL)
return NULL;
newnode->key = key;
newnode->data = data;
newnode->parent = NULL;
newnode->left = NULL;
newnode->right = NULL;
return newnode;
}
static inline int compare(uintptr_t key_a, uintptr_t key_b)
{
if (key_a > key_b)
return 1;
else if (key_a == key_b)
return 0;
else
return -1;
}
RbtNode* do_lookup(uintptr_t key,
RbtTree* tree,
RbtNode** pparent)
{
RbtNode* current = tree->root;
while (current) {
int ret = compare(current->key, key);
if (ret == 0)
return current;
else {
if (pparent != NULL) {
*pparent = current;
}
if (ret < 0)
current = current->right;
else
current = current->left;
}
}
return NULL;
}
RbtNode* rbt_search(RbtTree* tree, uintptr_t key)
{
RbtNode* node;
node = do_lookup(key, tree, NULL);
return node;
}
static void set_child(RbtTree* tree, RbtNode* node, RbtNode* child)
{
int ret = compare(node->key, child->key);
assert(ret != 0);
if (ret > 0) {
node->left = child;
} else {
node->right = child;
}
}
static void rotate_left(RbtNode* node, RbtTree* tree)
{
RbtNode* p = node;
RbtNode* q = node->right;
RbtNode* parent = node->parent;
if (parent == NULL) {
tree->root = q;
} else {
if (parent->left == p)
parent->left = q;
else
parent->right = q;
}
set_parent(parent, q);
set_parent(q, p);
p->right = q->left;
if (q->left)
set_parent(p, q->left);
q->left = p;
}
static void rotate_right(RbtNode* node, RbtTree* tree)
{
RbtNode* p = node;
RbtNode* q = node->left; /* can't be NULL */
RbtNode* parent = get_parent(p);
if (!is_root(p)) {
if (parent->left == p)
parent->left = q;
else
parent->right = q;
} else
tree->root = q;
set_parent(parent, q);
set_parent(q, p);
p->left = q->right;
if (p->left)
set_parent(p, p->left);
q->right = p;
}
void rbtree_init(RbtTree* tree)
{
tree->root = NULL;
tree->nr_ele = 0;
}
RbtNode* __rbtree_insert(RbtNode* node, RbtTree* tree)
{
RbtNode* samenode = NULL;
RbtNode* parent = NULL;
samenode = do_lookup(node->key, tree, &parent);
if (samenode != NULL)
return samenode;
node->left = node->right = NULL;
set_color(RED, node);
set_parent(parent, node);
if (parent == NULL)
tree->root = node;
else {
set_child(tree, parent, node);
}
while ((parent = get_parent(node)) != NULL && parent->color == RED) {
RbtNode* grandpa = get_parent(parent); // grandpa must be existed
// because root is black ,and parent is red,
// parent can not be root of tree. and parent is red,so grandpa must be black
if (parent == grandpa->left) {
RbtNode* uncle = grandpa->right;
if (uncle && get_color(uncle) == RED) {
set_color(RED, grandpa);
set_color(BLACK, parent);
set_color(BLACK, uncle);
node = grandpa;
} else {
if (node == parent->right) {
rotate_left(parent, tree);
node = parent;
parent = get_parent(parent);
}
set_color(BLACK, parent);
set_color(RED, grandpa);
rotate_right(grandpa, tree);
}
} else {
RbtNode* uncle = grandpa->left;
if (uncle && uncle->color == RED) {
set_color(RED, grandpa);
set_color(BLACK, parent);
set_color(BLACK, uncle);
node = grandpa;
} else {
if (node == parent->left) {
rotate_right(parent, tree);
node = parent;
parent = get_parent(node);
}
set_color(BLACK, parent);
set_color(RED, grandpa);
rotate_left(grandpa, tree);
}
}
}
set_color(BLACK, tree->root);
return NULL;
}
int rbt_insert(RbtTree* tree, uintptr_t key, void* data)
{
if (rbt_search(tree, key) != NULL) {
return RBTTREE_INSERT_EXISTED;
}
RbtNode* node = rbtree_createnode(key, data);
RbtNode* samenode = NULL;
if (node == NULL)
return RBTTREE_INSERT_FAILED;
else
samenode = __rbtree_insert(node, tree);
assert(samenode == NULL);
tree->nr_ele++;
return RBTTREE_INSERT_SECC;
}
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 RBTTREE_DELETE_FAILED;
else
__rbtree_remove(node, tree);
tree->nr_ele--;
if (rbt_is_empty(tree)) {
assert(tree->root == NULL);
}
return RBTTREE_DELETE_SUCC;
}
void rbt_traverse_inner(RbtNode* node, rbt_traverse_fn fn, void* data)
{
if (node == NULL) {
return;
}
if (fn(node, data)) {
rbt_traverse_inner(node->left, fn, data);
rbt_traverse_inner(node->right, fn, data);
}
}
void rbt_traverse(RbtTree* tree, rbt_traverse_fn fn, void* data)
{
rbt_traverse_inner(tree->root, fn, data);
}
@@ -64,7 +64,6 @@ __attribute__((optimize("O0"))) void dabort_handler(struct trapframe* r)
xizi_enter_kernel();
sys_exit(cur_task);
assert(cur_cpu()->task == NULL);
context_switch(&cur_task->thread_context.context, cur_cpu()->scheduler);
panic("dabort end should never be reashed.\n");
}
@@ -84,7 +83,6 @@ __attribute__((optimize("O0"))) void iabort_handler(struct trapframe* r)
xizi_enter_kernel();
sys_exit(cur_task);
assert(cur_cpu()->task == NULL);
context_switch(&cur_task->thread_context.context, cur_cpu()->scheduler);
panic("iabort end should never be reashed.\n");
}
@@ -34,8 +34,6 @@ Modification:
#include "multicores.h"
#include "task.h"
#include "log.h"
static struct TraceTag clock_driver_tag;
static struct XiziClockDriver* p_clock_driver = NULL;
@@ -46,6 +44,30 @@ bool clock_intr_handler_init(struct TraceTag* p_clock_driver_tag)
return p_clock_driver != NULL;
}
void hw_current_tick(uintptr_t* tick)
{
if (p_clock_driver == NULL) {
*tick = 0;
return;
}
*tick = p_clock_driver->get_tick();
}
void hw_current_second(uintptr_t* second)
{
if (p_clock_driver == NULL) {
*second = 0;
return;
}
*second = p_clock_driver->get_second();
}
bool count_down_sleeping_task(RbtNode* node, void* data)
{
/// @todo implement
return false;
}
uint64_t global_tick = 0;
int xizi_clock_handler(int irq, void* tf, void* arg)
{
@@ -53,14 +75,29 @@ int xizi_clock_handler(int irq, void* tf, void* arg)
if (p_clock_driver->is_timer_expired()) {
p_clock_driver->clear_clock_intr();
global_tick++;
// handle current thread
struct Thread* current_task = cur_cpu()->task;
if (current_task) {
current_task->remain_tick--;
current_task->maxium_tick--;
if (current_task->remain_tick == 0) {
xizi_task_manager.task_yield_noschedule(current_task, false);
struct ScheduleNode* snode = &current_task->snode;
snode->sched_context.remain_tick--;
if (snode->sched_context.remain_tick == 0) {
THREAD_TRANS_STATE(current_task, READY);
}
}
// todo: cpu 0 will handle sleeping thread
rbt_traverse(&g_scheduler.snode_state_pool[SLEEPING], count_down_sleeping_task, NULL);
// DOUBLE_LIST_FOR_EACH_ENTRY(thread, &xizi_task_manager.task_sleep_list_head, node)
// {
// assert(thread->state == SLEEPING);
// thread->sleep_context.remain_ms--;
// if (thread->sleep_context.remain_ms <= 0) {
// xizi_task_manager.task_unblock(thread);
// break;
// }
// }
}
return 0;
}
@@ -84,8 +84,8 @@ void intr_irq_dispatch(struct trapframe* tf)
// finish irq.
p_intr_driver->hw_after_irq(int_info);
if (cur_cpu()->task == NULL || current_task->state != RUNNING) {
cur_cpu()->task = NULL;
assert(cur_cpu()->task == current_task && current_task->snode.state == RUNNING);
if (!queue_is_empty(&current_task->snode.state_trans_signal_queue)) {
context_switch(&current_task->thread_context.context, cur_cpu()->scheduler);
}
assert(current_task == cur_cpu()->task);
@@ -56,7 +56,7 @@ void software_irq_dispatch(struct trapframe* tf)
/// @todo: Handle dead task
int syscall_num = -1;
if (cur_task && cur_task->state != DEAD) {
if (cur_task && cur_task->snode.state != DEAD) {
cur_task->thread_context.trapframe = tf;
// call syscall
@@ -64,8 +64,8 @@ void software_irq_dispatch(struct trapframe* tf)
arch_set_return(tf, ret);
}
if ((cur_cpu()->task == NULL && cur_task != NULL) || cur_task->state != RUNNING) {
cur_cpu()->task = NULL;
assert(cur_cpu()->task == cur_task && cur_task->snode.state == RUNNING);
if (!queue_is_empty(&cur_task->snode.state_trans_signal_queue)) {
context_switch(&cur_task->thread_context.context, cur_cpu()->scheduler);
}
if (syscall_num == SYSCALL_EXIT) {