2012年4月7日

【DIY kernel】實作 timer



timer 要做的事情也不難

了解整個過程之後code就比較好理解

首先 timer create 之後就將 timer 加入 timer_list

之後在每100個clock發生的interrupt內檢查timer_list

是否有timeout的timer和不是periodic mode(週期模式)的timer

發生timeout就執行 timeout handler

不是periodic mode 就設為inactive

然後還有額外的控制函數

timer_stop, timer_delete, timer_control(可控制timer mode)

接下來的code只會在比較特別的地方做講解!

先定義 timer 的結構和狀態


#define NAME_MAXLEN 20

struct timer{

node_t node;

char name[NAME_MAXLEN];
u8int flag;
void (*timeout_func)(void *parameter);
void *parameter;
u32int init_tick;
u32int timeout_tick;
};
typedef struct timer timer_t;

#define ACTIVATED 1<<0
#define PERIODIC 1<<1
typedef enum{
SET_TIME = 0,
GET_TIME,
SET_ONESHOT,
SET_PERIODIC
} TIMER_CMD_TYPE;


接下來就實作會用到的 function


void init_system_timer(){

init_list( &timer_list );

}



timer_t *timer_create( const char *name, void (*timeout)(void *parameter), void *parameter, u32int time, TIMER_CMD_TYPE flag ){

timer_t *timer = kmalloc( sizeof(timer_t) );
if( timer == NULL ){
kprintf("timer == NULL \n");
return NULL;
}else{
kprintf("timer != NULL \n");
}
timer_init(timer, name, timeout, parameter, time, flag);
return timer;
}

void timer_init( timer_t *timer, const char *name, void(*timeout)(void *parameter), void *parameter, u32int time, TIMER_CMD_TYPE flag ){
if( timer == NULL )
return;
switch(flag){
case SET_ONESHOT:
timer->flag &= ~PERIODIC;
break;
case SET_PERIODIC:
timer->flag |= PERIODIC;
break;
}
timer->flag &= ~ACTIVATED;
timer->timeout_func = timeout;
timer->parameter = parameter;
timer->timeout_tick = 0;
timer->init_tick = time;
}



timer_list 是個 list_t 型態的全域變數

list_t timer_list;


接著是實作 timer_start (將 timer 丟進 timer_list裡,並按照timeout大小排列)
和 timer_check (檢查timer_list是否有timeout的timer)


s8int timer_start( timer_t *timer ){

if( timer == NULL || timer->flag & ACTIVATED )

return ERROR;
timer_t *ptimer;
node_t *pnode, *last_node;
timer->timeout_tick = get_tick() + timer->init_tick;
disableInterrupt();
if( !is_Empty( &timer_list ) ){
pnode = first_node( &timer_list );
last_node = &timer_list.tail;
while( pnode != last_node || pnode == NULL ){
ptimer = (timer_t *)pnode;
if( ptimer->timeout_tick > timer->timeout_tick ){
append_list(pnode->prev, &timer->node);
break;
}else{
pnode = pnode->next;
}
}
if( pnode == last_node ){
insert_rear(&timer_list, &timer->node);
}
}else{
insert_rear(&timer_list, &timer->node);
}
enableInterrupt();
timer->flag |= ACTIVATED;
print_list(&timer_list);
return OK;
}

void timer_check(){
timer_t *ptimer;
node_t *pnode;
u32int current_tick = get_tick();
disableInterrupt();
if( !is_Empty(&timer_list) ){
pnode = first_node(&timer_list);
while( pnode != &timer_list.tail ){
ptimer = (timer_t *)pnode;
if( current_tick >= ptimer->timeout_tick ){
remove_node(&ptimer->node);
ptimer->timeout_func(ptimer->parameter);
if( (ptimer->flag & PERIODIC) && (ptimer->flag & ACTIVATED) ){
ptimer->flag &= ~ACTIVATED;
print_list(&timer_list);
timer_start(ptimer);
}else{
ptimer->flag &= ~ACTIVATED;
}
current_tick = get_tick();
pnode = pnode->next;
}else{
//kprintf("while break \n");
break;
}
}
}
enableInterrupt();
}


接下來是工具


s8int timer_stop( timer_t *timer ){

if( timer == NULL || !(timer->flag & ACTIVATED) )
return ERROR;
timer->flag &= ~ACTIVATED;
disableInterrupt();
remove_node(&timer->node);
enableInterrupt();
return OK;
}

s8int timer_delete( timer_t *timer ){
if( timer == NULL )
return ERROR;
disableInterrupt();
remove_node(&timer->node);
enableInterrupt();
kfree(timer);
return OK;
}

s8int timer_control( timer_t *timer, TIMER_CMD_TYPE cmd, u32int arg ){
if( timer == NULL )
return ERROR;
switch( cmd ){
case SET_TIME:
timer->init_tick = arg;
break;
case GET_TIME:
return timer->init_tick;
case SET_ONESHOT:
timer->flag &= ~PERIODIC;
break;
case SET_PERIODIC:
timer->flag |= PERIODIC;
break;
default:
return ERROR;
}
return OK;
}



我在gitHub上開了個 project
有興趣的人可以去看看

沒有留言:

張貼留言