2012年4月8日

【DIY kernel】為context switch做準備, 實作Task



這部分程式已經提交到gitHub

故不將所有程式碼貼在網誌上瞜~~



task 共有四種狀態,分別是 ready, running, block(類似在休息, 記憶體不會被釋放), close

目前無法真正的將cpu使用權切換給其他task使用

只能修改各task的狀態

等下次將context switch實作之後才會有作用

這部分程式主要就是在這些狀態中切換

所以需要

list_t ready_list[MAX_PRIO];
list_t blocked_list;
list_t termination_list;

這三種list紀錄某種狀態下有哪些task

然後用

u32int task_table[MAX_TASK_NUM];

來放所有task, 有task設為1其餘為0 (所以這個os只能run MAX_TASK_NUM 個 task)

最後還有一個

u8int prioExistFlag[MAX_PRIO];

這是為了取出priority最高的 ready_list 所建的table (array)。

task 的結構如下


struct task{
node_t node;

void *sp;
void *entry;
void *parameter;
void *stack_addr;
u16int stack_size;

u8int priority;

u32int init_tick;
u32int remaining_tick;

u32int task_id;
TASK_STATE state;
char name[NAME_MAXLENTH];

timer_t *timer;
};

比較特別的是 void *sp (stack point)這指向 task 的 stack

void *entry 這指向這task要做的事情的function

void *stack_addr 就是指向stack的開頭摟

總共要實作的function有這些


task_t *task_create( const char *name,
void (*entry)(void *parameter),
void *parameter,
u16int stackSize,
u8int priority,
u16int tick);
s8int task_start( task_t *task );
s8int task_delete( task_t *task );
void task_yield();
s8int task_sleep( u32int tick );
s8int task_suspend( task_t *task );
s8int task_resume( task_t *task );
void task_remove( task_t *task );
void task_addReady( task_t *task );
task_t *ready_task( u8int priority );
u8int get_top_prio();
u32int get_task_id();

static void task_timeout(void *parameter);

在task_create裡


task_t *task_create( const char *name,
void (*entry)(void *parameter),
void *parameter,
u16int stackSize,
u8int priority,
u16int tick){

task_t *task;
u32int *stackAddr;
u32int task_id;

task_id = get_task_id();
if( task_id < 0 ){
return NULL;
}

task = (task_t *)kmalloc(sizeof(task_t));
if(task == NULL)
return NULL;

stackAddr = (void *)kmalloc(stackSize);
if( stackAddr == NULL ){
kfree(task);
return NULL;
}

for( int temp=0; temp<NAME_MAXLENTH; temp++ ){
task->name[temp] = name[temp];
}

task->task_id = task_id;
task->entry = (void *)entry;
task->parameter = parameter;
task->stack_addr = stackAddr;
task->stack_size = stackSize;
task->node.next = NULL;
task->node.prev = NULL;

task->init_tick = tick;
task->remaining_tick = tick;
task->priority = priority;
task->sp = (void *)( (void *)stackAddr + stackSize -4 );

memset( (u8int *)task->stack_addr, '?', task->stack_size );
task->sp = (void *)init_stack(task->sp,
 task->entry,
 task->parameter);
task_table[task->task_id] = 1;

task->timer = timer_create(task->name,
  task_timeout,
  task,
  0,
  SET_ONESHOT);

return task;
}

首先會取得task_id

就是從task_table裡取出value是0的key

之後就是初始化的動作

其中的init_stack在下次context switch時再一併講解

其餘工具的演算法或流程也不難

從一個狀態切換到下個狀態主要是

從原本的list裡移除(critical region)再加入另一個狀態的list中

詳細程式碼請至gitHub下載或線上參考~~

https://github.com/herb123456/DIY_Kernel

============================================

後來想想,還是直接在這寫下 init_stack 吧XD

init_stack在 stack.c 裡實作

是每個 task 專屬的一塊記憶體

裡面放的東西長這樣:


之後context switch 時 會將程式狀態存在這塊stack裡

詳細流程會在下一篇在講~~

1 則留言: