커널단에서 init_timer 이용해서 timer 돌리는데요. 자꾸 에러가 나요
글쓴이: jgm2000 / 작성시간: 금, 2007/01/12 - 11:37오전
init_timer 이용해서 add 해주고 expires, func 선언 다 해주었습니다.
타이머는 잘 돌아가는데요.
func에서 sys_open을 해 놓게 만들었습니다.
일정 시간 지나면 sys_open을 호출하게요.
근데 sys_open을 하게되면 커널 에러가 뜨면서 리눅스가 죽어버려요.
func 내에서 sys_open 호출 안하고 다른 루틴에서 호출하면 안죽거든요.
유독 timer 내의 func에서 호출할때면 죽네요?
원인이 뭘까요?
아시는 분 계시면 답변 부탁드립니다.
Forums:
sys_open 은: asmlinkage
sys_open 은:
asmlinkage long sys_open(const char __user *filename, int flags, int mode)
이므로 sys_open에 전달하는 첫번째 인자는 포인터가 user's address space를 가리키는 포인터여야 합니다.
그냥 커널 주소를 가리키는 포인터를 사용하시면 엉뚱한 주소값을 접근하게 되서 커널이 죽겠지요.
set_fs(KERNEL_DS)를 해도 그런가요?
set_fs(KERNEL_DS)를 해주는데도 그런가요?
sys_open을 커널 모듈에서 잘 썼었거든요.
문제는 timer에 등록된 함수에서 사용할 때만 이런 에러가 나는건데요.
해결법이 없을까요?
static int myserial_open(void)
{
old_fs = get_fs();
set_fs(KERNEL_DS);
handle = sys_open("/dev/ttyUSB0", O_RDWR, 644);
if( handle < 0 ) {
handle = 0;
set_fs(old_fs);
printk("Serial Open Fail [%s]\n", device_name);
return -1;
}
else {
printk("Seial Open Success....\n");
filep = fget(handle);
ttyp = filep->private_data;
filep->f_pos = pos;
return 0;
}
}
void time_func(unsigned long key)
{
if( key == 777 )
{
printk("timer....%d\n", timeseq++);
init_timer(&usngw_mod_timer);
usngw_mod_timer.expires = get_jiffies_64() + 5 * HZ;
usngw_mod_timer.data = 777;
usngw_mod_timer.function = time_func;
add_timer(&usngw_mod_timer);
}
if((myserial_open()) < 0)
printk("Serial Open Failure...\n");
}
이렇게 했는데 myserial_open 해서 커널 에러가 나는 거 같습니다.
타이머 말고 kernel thread를 사용하세요.
타이머에서 open 같은 호출을 하는 것은 위험합니다. (중간에 대기 상태로 빠질 수도 있으므로..)
대기 상태를 허용하는 kernel thread를 사용하시는 편이 좋을 것으로 보입니다. (thread loop내에서
필요한 시간만큼 wait를 주어 타이밍을 맞출 수 있습니다.)
int kwdtd(void *unused) {
int kwdtd(void *unused)
{
daemonize();
for (;;)
{
printk(KERN_DEBUG "What's going on, kernel!\n");
schedule_timeout(2);
}
}
int init_module(void)
{
kernel_thread(kwdtd, NULL, 0);
printk(KERN_DEBUG "Hello, kernel!\n");
return 0;
}
void cleanup_module(void)
{
printk(KERN_DEBUG "Good-bye, kernel!\n");
}
님 말씀대로 kernel thread를 이용해서 할려고 위에 예제를 이용했는데요.
daemonize에서 인자가 더 필요하다고 나오네요
커널 2.6대를 쓰는데 실제로 linux/sched.h 에 들어가보니 daemonize에 인자가 있던데
여기 들어가는 인자들은 무엇인가요?
timer 핸들러는
timer 핸들러는 인터럽트 컨텍스트입니다.
구현마다 다를 순 있겠지만, OS tick timer 인터럽트에서 호출됩니다.
커널 쓰레드를 따로 만드시는 것이 속 편하긴하나,
그와 같은 반복작업을 피하고자 만들어진 설비들이 있습니다.
2.4 에서는 약간 부족한 감이 있으나,
2.6 으로 올라오면서 이름이 바뀌면서 편의설비들이 추가되기도 했습니다.
올려주신 소스가 불완전하여 정확한 판단은 어렵지만,
여러가지 부적절한 점이 있는 것 같기도 합니다.
daemonize() 의 구현은 kernel/exit.c 에 있으며,
아규먼트는 쓰레드의 이름입니다.
daemonize("kkldpd");
daemonize("kkldpd_for_%s@%lu", UTS_RELEASE, jiffies);
queue_delayed_work()를 써봄이...
윗 분 말씀마따나 kernel dynamic timer는 IRQ context에서
동작하므로 시스템 콜을 부르면 문제가 발행합니다.
queue_delayed_work()를 써봄이 어떨까요?
kernel thread 방식으로 돌고 패러미터로 delay time을 입력할 수 있습니다.
/***************************************
Being the one is just like being in love.
***************************************/
댓글 달기