forked from xuos/xiuos
Update free thread
This commit is contained in:
parent
02f6a412de
commit
2f54409819
|
@ -36,6 +36,10 @@ Modification:
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "task.h"
|
#include "task.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
INVALID_SESS_ID = 0,
|
||||||
|
};
|
||||||
|
|
||||||
/// @brief userland session info copy
|
/// @brief userland session info copy
|
||||||
struct Session {
|
struct Session {
|
||||||
uintptr_t id;
|
uintptr_t id;
|
||||||
|
@ -68,7 +72,7 @@ struct client_session {
|
||||||
struct session_backend {
|
struct session_backend {
|
||||||
struct server_session server_side;
|
struct server_session server_side;
|
||||||
struct client_session client_side;
|
struct client_session client_side;
|
||||||
int session_id; // id of this session
|
uintptr_t session_id; // id of this session
|
||||||
int nr_pages; // pages used by this pipe
|
int nr_pages; // pages used by this pipe
|
||||||
struct Thread* client; // client of this pipe
|
struct Thread* client; // client of this pipe
|
||||||
struct Thread* server; // server of this pipe
|
struct Thread* server; // server of this pipe
|
||||||
|
@ -93,22 +97,5 @@ extern struct XiziSharePageManager xizi_share_page_manager;
|
||||||
|
|
||||||
int module_share_page_init(struct SharePageRightGroup* right_group);
|
int module_share_page_init(struct SharePageRightGroup* right_group);
|
||||||
|
|
||||||
static inline void client_close_session(struct Thread* thd, struct client_session* cli_sess)
|
void client_close_session(struct Thread* thd, struct client_session* cli_sess);
|
||||||
{
|
void server_close_session(struct Thread* thd, struct server_session* svr_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,7 +48,8 @@ Modification:
|
||||||
#define SLEEP_MONITOR_CORE 0
|
#define SLEEP_MONITOR_CORE 0
|
||||||
|
|
||||||
enum ProcState {
|
enum ProcState {
|
||||||
INIT = 0,
|
UNINIT = 0,
|
||||||
|
INIT,
|
||||||
READY,
|
READY,
|
||||||
RUNNING,
|
RUNNING,
|
||||||
DEAD,
|
DEAD,
|
||||||
|
@ -133,7 +134,7 @@ struct TaskLifecycleOperations {
|
||||||
/* new a task control block, checkout #sys_spawn for usage */
|
/* new a task control block, checkout #sys_spawn for usage */
|
||||||
struct Thread* (*new_thread)(struct MemSpace* pmemspace);
|
struct Thread* (*new_thread)(struct MemSpace* pmemspace);
|
||||||
/* free a task control block, this calls #free_user_pgdir to free all vitual spaces */
|
/* free a task control block, this calls #free_user_pgdir to free all vitual spaces */
|
||||||
void (*free_pcb)(struct Thread*);
|
void (*free_thread)(struct Thread*);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct XiziTaskManager {
|
struct XiziTaskManager {
|
||||||
|
|
|
@ -204,7 +204,7 @@ void unmap_task_share_pages(struct Thread* task, const uintptr_t task_vaddr, con
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int next_session_id = 1;
|
static int next_session_id = INVALID_SESS_ID + 1;
|
||||||
struct session_backend* create_share_pages(struct Thread* client, struct Thread* server, const int capacity)
|
struct session_backend* create_share_pages(struct Thread* client, struct Thread* server, const int capacity)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -362,3 +362,27 @@ int module_share_page_init(struct SharePageRightGroup* _right_group)
|
||||||
right_group = *_right_group;
|
right_group = *_right_group;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
uintptr_t sess_id = sess_backend->session_id;
|
||||||
|
cli_sess->closed = true;
|
||||||
|
xizi_share_page_manager.delete_share_pages(sess_backend);
|
||||||
|
assert(NULL == rbt_search(&thd->cli_sess_map, sess_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
uintptr_t sess_id = sess_backend->session_id;
|
||||||
|
svr_sess->closed = true;
|
||||||
|
xizi_share_page_manager.delete_share_pages(sess_backend);
|
||||||
|
assert(NULL == rbt_search(&thd->svr_sess_map, sess_id));
|
||||||
|
}
|
|
@ -43,7 +43,7 @@ int sys_exit(struct Thread* ptask)
|
||||||
// free that task straightly if it's a blocked task
|
// free that task straightly if it's a blocked task
|
||||||
if (ptask->state == BLOCKED) {
|
if (ptask->state == BLOCKED) {
|
||||||
struct TaskLifecycleOperations* tlo = GetSysObject(struct TaskLifecycleOperations, &xizi_task_manager.task_lifecycle_ops_tag);
|
struct TaskLifecycleOperations* tlo = GetSysObject(struct TaskLifecycleOperations, &xizi_task_manager.task_lifecycle_ops_tag);
|
||||||
tlo->free_pcb(ptask);
|
tlo->free_thread(ptask);
|
||||||
}
|
}
|
||||||
// yield current task in case it wants to exit itself
|
// yield current task in case it wants to exit itself
|
||||||
xizi_task_manager.task_yield_noschedule(cur_cpu()->task, false);
|
xizi_task_manager.task_yield_noschedule(cur_cpu()->task, false);
|
||||||
|
|
|
@ -40,9 +40,9 @@ int sys_new_thread(struct MemSpace* pmemspace, struct Thread* task, uintptr_t en
|
||||||
struct ThreadStackPointer loaded_sp = load_user_stack(pmemspace, argv);
|
struct ThreadStackPointer loaded_sp = load_user_stack(pmemspace, argv);
|
||||||
if (loaded_sp.stack_idx == -1) {
|
if (loaded_sp.stack_idx == -1) {
|
||||||
ERROR("Uable to load params to memspace.\n");
|
ERROR("Uable to load params to memspace.\n");
|
||||||
/* memspace is freed alone with free_pcb() */
|
/* memspace is freed alone with free_thread() */
|
||||||
struct TaskLifecycleOperations* tlo = GetSysObject(struct TaskLifecycleOperations, &xizi_task_manager.task_lifecycle_ops_tag);
|
struct TaskLifecycleOperations* tlo = GetSysObject(struct TaskLifecycleOperations, &xizi_task_manager.task_lifecycle_ops_tag);
|
||||||
tlo->free_pcb(task);
|
tlo->free_thread(task);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -236,7 +236,7 @@ struct ThreadStackPointer load_user_stack(struct MemSpace* pmemspace, char** arg
|
||||||
}
|
}
|
||||||
|
|
||||||
/* allocate memory space for user stack */
|
/* allocate memory space for user stack */
|
||||||
uintptr_t* stack_bottom = (uintptr_t*)kalloc(USER_STACK_SIZE);
|
uintptr_t* stack_bottom = (uintptr_t*)kalloc_by_ownership(pmemspace->kernspace_mem_usage.tag, USER_STACK_SIZE);
|
||||||
if (UNLIKELY(stack_bottom == NULL)) {
|
if (UNLIKELY(stack_bottom == NULL)) {
|
||||||
ERROR("No memory to alloc user stack.\n");
|
ERROR("No memory to alloc user stack.\n");
|
||||||
handle_error_stack_loading(pmemspace, stack_idx, stack_bottom, false);
|
handle_error_stack_loading(pmemspace, stack_idx, stack_bottom, false);
|
||||||
|
|
|
@ -49,7 +49,7 @@ struct Thread* max_priority_runnable_task(void)
|
||||||
} else if (task->dead && task->state != RUNNING) {
|
} else if (task->dead && task->state != RUNNING) {
|
||||||
|
|
||||||
struct TaskLifecycleOperations* tlo = GetSysObject(struct TaskLifecycleOperations, &xizi_task_manager.task_lifecycle_ops_tag);
|
struct TaskLifecycleOperations* tlo = GetSysObject(struct TaskLifecycleOperations, &xizi_task_manager.task_lifecycle_ops_tag);
|
||||||
tlo->free_pcb(task);
|
tlo->free_thread(task);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ struct Thread* round_robin_runnable_task(uint32_t priority)
|
||||||
return task;
|
return task;
|
||||||
} else if (task->dead && task->state != RUNNING) {
|
} else if (task->dead && task->state != RUNNING) {
|
||||||
struct TaskLifecycleOperations* tlo = GetSysObject(struct TaskLifecycleOperations, &xizi_task_manager.task_lifecycle_ops_tag);
|
struct TaskLifecycleOperations* tlo = GetSysObject(struct TaskLifecycleOperations, &xizi_task_manager.task_lifecycle_ops_tag);
|
||||||
tlo->free_pcb(task);
|
tlo->free_thread(task);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,54 +99,6 @@ static void _task_manager_init()
|
||||||
ready_task_priority = 0;
|
ready_task_priority = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _task_return_sys_resources(struct Thread* ptask)
|
|
||||||
{
|
|
||||||
assert(ptask != NULL);
|
|
||||||
|
|
||||||
/* handle sessions for condition 1, ref. delete_share_pages() */
|
|
||||||
// close all server_sessions
|
|
||||||
while (!IS_DOUBLE_LIST_EMPTY(&ptask->svr_sess_listhead)) {
|
|
||||||
// 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));
|
|
||||||
if (server_to_info->state == BLOCKED) {
|
|
||||||
xizi_task_manager.task_unblock(session_backend->server);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
assert(DeleteResource(&ptask->server_identifier, &server_identifier_owner));
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete registered irq if there is one
|
|
||||||
if (ptask->bind_irq) {
|
|
||||||
sys_unbind_irq_all(ptask);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern void trap_return(void);
|
extern void trap_return(void);
|
||||||
__attribute__((optimize("O0"))) void task_prepare_enter()
|
__attribute__((optimize("O0"))) void task_prepare_enter()
|
||||||
{
|
{
|
||||||
|
@ -162,38 +114,104 @@ static void _free_thread(struct Thread* task)
|
||||||
ERROR("deallocating a NULL task\n");
|
ERROR("deallocating a NULL task\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
assert(task->state >= INIT);
|
||||||
|
assert(task->memspace != NULL);
|
||||||
|
|
||||||
_task_return_sys_resources(task);
|
// ignore [name, tid, dead, ]
|
||||||
|
// case thread context [kern_stack_addr, ]
|
||||||
|
|
||||||
|
/* 1. close all ipcall sessions */
|
||||||
|
ERROR_FREE
|
||||||
|
{
|
||||||
|
/* handle sessions for condition 1, ref. delete_share_pages() */
|
||||||
|
// close all server_sessions
|
||||||
|
while (!IS_DOUBLE_LIST_EMPTY(&task->svr_sess_listhead)) {
|
||||||
|
// RbtNode* sess_ref_node = ptask->svr_sess_map.root;
|
||||||
|
struct server_session* svr_session = CONTAINER_OF(task->svr_sess_listhead.next, struct server_session, node);
|
||||||
|
server_close_session(task, svr_session);
|
||||||
|
}
|
||||||
|
|
||||||
|
// close all client_sessions
|
||||||
|
while (!IS_DOUBLE_LIST_EMPTY(&task->cli_sess_listhead)) {
|
||||||
|
// RbtNode* sess_ref_node = ptask->cli_sess_map.root;
|
||||||
|
struct client_session* cli_session = CONTAINER_OF(task->cli_sess_listhead.next, struct client_session, node);
|
||||||
|
client_close_session(task, 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));
|
||||||
|
if (server_to_info->state == BLOCKED) {
|
||||||
|
xizi_task_manager.task_unblock(session_backend->server);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(IS_DOUBLE_LIST_EMPTY(&task->svr_sess_listhead));
|
||||||
|
assert(IS_DOUBLE_LIST_EMPTY(&task->cli_sess_listhead));
|
||||||
|
// assert(rbt_is_empty(&task->svr_sess_map));
|
||||||
|
// assert(rbt_is_empty(&task->cli_sess_map));
|
||||||
|
|
||||||
|
/// @todo handle server transition
|
||||||
|
/* delete server identifier */
|
||||||
|
if (task->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);
|
||||||
|
assert(DeleteResource(&task->server_identifier, &server_identifier_owner));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 2. quit interrupt handling */
|
||||||
|
ERROR_FREE
|
||||||
|
{
|
||||||
|
// delete registered irq if there is one
|
||||||
|
if (task->bind_irq) {
|
||||||
|
sys_unbind_irq_all(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 3. quit schedule */
|
||||||
|
ERROR_FREE
|
||||||
|
{
|
||||||
|
// remove thread from used task list
|
||||||
|
task_node_leave_list(task);
|
||||||
|
/// ignore [ticks, sleep context, state]
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 3. free context */
|
||||||
|
ERROR_FREE
|
||||||
|
{
|
||||||
|
/* free thread's kernel stack */
|
||||||
|
assert(task->thread_context.kern_stack_addr != (uintptr_t)NULL);
|
||||||
|
assert(kfree_by_ownership(task->memspace->kernspace_mem_usage.tag, (void*)task->thread_context.kern_stack_addr));
|
||||||
|
|
||||||
/* free thread's user stack */
|
/* free thread's user stack */
|
||||||
if (task->thread_context.user_stack_idx != -1) {
|
if (task->thread_context.user_stack_idx != -1) {
|
||||||
// stack is mapped in vspace, so it should be freed from pgdir
|
// stack is mapped in vspace, so it should be freed from pgdir
|
||||||
assert(task->thread_context.user_stack_idx >= 0 && task->thread_context.user_stack_idx < 64);
|
|
||||||
assert(task->memspace != NULL);
|
assert(task->memspace != NULL);
|
||||||
|
assert(task->thread_context.user_stack_idx >= 0 && task->thread_context.user_stack_idx < 64);
|
||||||
|
|
||||||
/* the stack must have be set in memspace if bitmap has been set */
|
/* the stack must have be set in memspace if bitmap has been set */
|
||||||
assert(xizi_pager.unmap_pages(task->memspace->pgdir.pd_addr, task->thread_context.uspace_stack_addr, USER_STACK_SIZE));
|
assert(xizi_pager.unmap_pages(task->memspace->pgdir.pd_addr, task->thread_context.uspace_stack_addr, USER_STACK_SIZE));
|
||||||
bitmap64_free(&task->memspace->thread_stack_idx_bitmap, task->thread_context.user_stack_idx);
|
bitmap64_free(&task->memspace->thread_stack_idx_bitmap, task->thread_context.user_stack_idx);
|
||||||
/* thread's user stack space is also allocated for kernel free space */
|
/* thread's user stack space is also allocated for kernel free space */
|
||||||
assert(kfree((char*)task->thread_context.ustack_kvaddr));
|
assert(kfree_by_ownership(task->memspace->kernspace_mem_usage.tag, (char*)task->thread_context.ustack_kvaddr));
|
||||||
|
|
||||||
if (task->memspace != NULL) {
|
|
||||||
task->memspace->mem_size -= USER_STACK_SIZE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove thread from used task list
|
|
||||||
task_node_leave_list(task);
|
|
||||||
|
|
||||||
/* free memspace if needed to */
|
/* free memspace if needed to */
|
||||||
if (task->memspace != NULL) {
|
doubleListDel(&task->memspace_list_node);
|
||||||
/* free thread's kernel stack */
|
/* free memspace if thread is the last one using it */
|
||||||
if (task->thread_context.kern_stack_addr) {
|
if (IS_DOUBLE_LIST_EMPTY(&task->memspace->thread_list_guard)) {
|
||||||
// kfree_by_ownership(task->memspace->kernspace_mem_usage.tag, (char*)task->thread_context.kern_stack_addr);
|
// free memspace
|
||||||
}
|
free_memspace(task->memspace);
|
||||||
|
} else if (task->memspace->thread_to_notify != NULL) {
|
||||||
// awake deamon in this memspace
|
// 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 != task) {
|
||||||
if (task->memspace->thread_to_notify->state == BLOCKED) {
|
if (task->memspace->thread_to_notify->state == BLOCKED) {
|
||||||
xizi_task_manager.task_unblock(task->memspace->thread_to_notify);
|
xizi_task_manager.task_unblock(task->memspace->thread_to_notify);
|
||||||
|
@ -205,17 +223,11 @@ static void _free_thread(struct Thread* task)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
doubleListDel(&task->memspace_list_node);
|
|
||||||
|
|
||||||
/* free memspace if thread is the last one using it */
|
|
||||||
if (IS_DOUBLE_LIST_EMPTY(&task->memspace->thread_list_guard)) {
|
|
||||||
// free memspace
|
|
||||||
free_memspace(task->memspace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// free task back to allocator
|
// free task back to allocator
|
||||||
|
ERROR_FREE
|
||||||
|
{
|
||||||
slab_free(&xizi_task_manager.task_allocator, (void*)task);
|
slab_free(&xizi_task_manager.task_allocator, (void*)task);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* alloc a new task with init */
|
/* alloc a new task with init */
|
||||||
|
@ -280,12 +292,13 @@ static struct Thread* _new_thread(struct MemSpace* pmemspace)
|
||||||
// [name]
|
// [name]
|
||||||
// [schedule related]
|
// [schedule related]
|
||||||
|
|
||||||
|
task->state = INIT;
|
||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TaskLifecycleOperations task_lifecycle_ops = {
|
struct TaskLifecycleOperations task_lifecycle_ops = {
|
||||||
.new_thread = _new_thread,
|
.new_thread = _new_thread,
|
||||||
.free_pcb = _free_thread,
|
.free_thread = _free_thread,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void _task_set_default_schedule_attr(struct Thread* task)
|
static void _task_set_default_schedule_attr(struct Thread* task)
|
||||||
|
@ -311,7 +324,7 @@ extern void context_switch(struct context**, struct context*);
|
||||||
static void _scheduler(struct SchedulerRightGroup right_group)
|
static void _scheduler(struct SchedulerRightGroup right_group)
|
||||||
{
|
{
|
||||||
struct MmuCommonDone* p_mmu_driver = AchieveResource(&right_group.mmu_driver_tag);
|
struct MmuCommonDone* p_mmu_driver = AchieveResource(&right_group.mmu_driver_tag);
|
||||||
// struct XiziTrapDriver* p_intr_driver = AchieveResource(&right_group.intr_driver_tag);
|
// struct XiziTrapDriver* p_intr_driver = AchieveResource(&right_group.intr_driver_tag);
|
||||||
struct Thread* next_task;
|
struct Thread* next_task;
|
||||||
struct CPU* cpu = cur_cpu();
|
struct CPU* cpu = cur_cpu();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue