Update XiZi_AIoT Kernel from tuyuyang
it is OK
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 = ¤t_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(¤t_task->snode.state_trans_signal_queue)) {
|
||||
context_switch(¤t_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) {
|
||||
|
||||
Reference in New Issue
Block a user