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 |