반응형
하드웨어 상태를 주기적으로 감시할때 정해진 시간이 초과되면 특정 함수를 수행하는 기능을 한다. 리눅스 커널은 타이머 인터럽트가 발생하며 스케줄링에 필요한 처리를 끝낸 후 커널 타이머 목록이라는 데이터 구조를 검사하며, 이 커널 타이머 목록은 수행할 함수와 처리되어야 할 시간에 대한 정보가 담긴 연결 리스트이다.

커널 타이머 이용시

struct timer_list : 커널 타이머 구조체
init_timer(): 커널 타이머 구초제를 초기화 한다
add_timer(): 커널 타이머에 수행될 함수를 등록한다
del_timer(): 커널 타이머 목록에서 등록된 것을 제거한다.

커널 타이머는 동작 시간이 1/Hz 단위로 1/Hz초 이하의 호출 주기는 사용이 불가능 하다

다음은 커널 2.6 버젼에서의 타이머 동작이다.
사용자 삽입 이미지

struct time_list 변수는
1. unsigned long expires, 2 unsigned long data, void (*function)(unsigned long)을 일반적으로 지정하여 사용한다.
1. unsigned long expires 는 다음과 같이 초기화 한다
 kerneltime.expires=get_jiffies_64()+(3*HZ/10);
 (현재 jiffies값을 얻어서 0.03초가 지난후로 설정)
2. unsigned long data 는 timer 함수에 전달할 데이터를 참조하기 위한 주소를 리턴한다.
3. void (*function)(unsigned long)는 타이머 시간이 만료하고 수행할 함수이다.

init_timer는 timer 구조체를 초기화 한다. 앞에서 설명한 expires,data,function 필드를 초기화 한다.

add_timer는 커널 타이머에 호출될 timer_list 구조체를 등록한다.

del_timer는 커널 타이머를 제거한다. 일반적으로 커널 타이머가 등록되고 시간이 초과하여 커널 타이머에 등록된 함수가 호출되면 등록된 커널 타이머는 자동적으로 제거된다. 하지만 디바이스 드라이버는 등록된 커널 타이머가 확실하게 후출되어 제거될 것이라는 확신이 있더라도 모듈 형식으로 디바이스 드라이버를 작성할 경우 디바이스 드라이버의 종료 루틴에 del_timer() 함수를 호출하여 모듈이 제거 되었을때 제거된 번지에 속해 있던 함수가 호출되지 않도록 하여야 한다.

커널 타이머 예
1초마다 메시지를 출력한다
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/time.h>
#include <linux/timer.h>
#define   TIME_STEP                       (1*HZ)
struct timer_list  *timer;
static int timertick=0;
void kerneltimer_timeover(unsigned long arg ); <--Timerover 시 실행할 함수
void kerneltimer_registertimer(struct timer_list* ptimer, unsigned long timeover )
{
     init_timer( ptimer );
     ptimer->expires  = get_jiffies_64() + timeover;
     ptimer->data     = NULL;
     ptimer->function = kerneltimer_timeover       ;

     add_timer( ptimer);
}
void kerneltimer_timeover(unsigned long arg )
{
        printk("I am timer tick:%d\n",timertick);
        timertick++;
        kerneltimer_registertimer( timer, TIME_STEP ); <--timerover 하면 재 등록
}
int kerneltimer_init(void)
{
    timer= kmalloc( sizeof( struct timer_list ), GFP_KERNEL );
    if( timer== NULL ) return -ENOMEM;
    memset( timer, 0, sizeof( struct timer_list) );
    kerneltimer_registertimer( timer,TIME_STEP );
    return 0;
}
void kerneltimer_exit(void)
{
    if( timer!= NULL )
    {
        del_timer( timer) ;
        kfree( timer);
    }
}
module_init(kerneltimer_init);
module_exit(kerneltimer_exit);
MODULE_LICENSE("Dual BSD/GPL");
반응형
Posted by alias
,