interrupt handler 안에서는 blocking을 유발하는 함수를 쓰지 않는다. 빠르게 처리되어야 한다.
다른 곳까지 영향을 미칠 수 있다. 예를 들어 kmalloc 함수 호출시 block이 된다.

즉, 아래와 같은 코드 예제에서.. interrupt가 실행되어 특정 변수에 그 값을 저장하고, read에서는 계속 while 문으로 돌아가게 하는 것은 block되게 한다는 의미이다. 


volatile unsigned int flag_ost1_int = 0;

void ost1_interrupt(int irq, void *dev_id, struct pt_regs *regs) {
printk("os timer1 interrupt\n");
OST1_TIMER_OFF;
flag_ost1_int = 1;
}


ssize_t fnd_read (struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
short data;

OST1_TIMER_ON;
while (!flag_ost1_int) {
;
}
}



문제를 해결하는 방법은 두가지가 있다. 하나는 application에서 nonblock 모드로 open하는 경우,
다른 두번째는 blocking io를 쓰더라도 다른 프로세스에 영향을 주지 않도록 대기큐를 이용해서 sleep 과 wakeup 을 사용해야 하는 방법이다.

첫번째 방법 nonblock 모드를 쓰는 경우이다.

sleep 때문에 영향을 주기 때문에 application 에서 noblock에서 써서 1초간격으로 sleep되게 할 수 있다..

어플 코드
 

        //fd = open("/dev/FND", O_RDWR);
      ->   fd = open("/dev/FND", O_RDWR|O_NONBLOCK);



            //if(read(fd, (void *)&data, sizeof(data))) break;
        ->    if(read(fd, (void *)&data, sizeof(data)) > 0) break;
               sleep(1);


 

커널 모듈 코드


ssize_t fnd_read (struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
short data;

    printk("OST Int. Waiting(%d)...\n", flag_ostInt);


OST_TIMER_ON;

    //while(!flag_ostInt) {
    // ;
    //}
// -> 
    while(!flag_ostInt) {
        if(filp->f_flags & O_NONBLOCK) {
            printk("O_NONBLOCK(%d)!\n", -EAGAIN);
            return -EAGAIN;
        }
    
   }


        
두번째 방법이다.  application이 아닌 내부에서 처리가 되게 해야 한다.

어플 코드 

fd = open("/dev/FND", O_RDWR);



커널 모듈 소스
대기 큐를 하나 생성하고 block 모드일때는 sleep 시킨다.



#include <linux/wait.h>
DECLARE_WAIT_QUEUE_HEAD(wq_read);

ssize_t fnd_read (struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
short data;

    printk("OST Int. Waiting(%d)...\n", flag_ostInt);


OST_TIMER_ON;

    //while(!flag_ostInt) {
    // ;
    //}
// -> 
    while(!flag_ostInt) {
        if(filp->f_flags & O_NONBLOCK) {
            printk("O_NONBLOCK(%d)!\n", -EAGAIN);
            return -EAGAIN;
        }
        
        // if not nonblock, use waiting queue
        interruptible_sleep_on(&wq_read);  // cpu를 놓아둔다.
    }

    data = FND_CS0;
    
    printk("OST Int Happened(%04x)...\n", data);
    copy_to_user(buf, &data, count);


     flag_ostInt = 0;
return(count);
}



그리고, interrupt 코드안에 wake_up코드를 추가한다.

void ost_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
printk("OST Int...\n");
OST_TIMER_OFF;
    flag_ostInt = 1;
    wake_up_interruptible(&wq_read);
}



'c or linux' 카테고리의 다른 글

[공부중] queue_task 예제  (0) 2011.04.21
[공부중] poll 함수 예제  (0) 2011.04.21
[공부중] header 파일 -irqs.h  (0) 2011.04.20
CPU 구성요소  (0) 2011.04.20
[공부중] OS Timer 예제 - interrupt  (0) 2011.04.20
Posted by '김용환'
,