Chinaunix

标题: 求教wake_up_interruptible相关的问题! [打印本页]

作者: liuchang1881    时间: 2006-07-03 11:22
标题: 求教wake_up_interruptible相关的问题!
在2410开发板上自己写了一个驱动程序,
我在用户空间read一个设备,在这个设备的read函数中用了wait_event_interruptible(wq,flags!=0);
当外部中断IRQ5发生时,在中断服务程序中执行flags=1;wake_up_interruptible(&wq);
现在当产生外部中断时,可以响应中断,但是程序一执行到wake_up_interruptible(&wq)时就死机!
程序开始时,静态声明了static DECLARE_WAIT_QUEUE_HEAD(wq);
我的 内核是 2.4.18,用模块调试设备驱动程序.
查了很多资料也没搞清楚为什么,请大家帮忙看看是哪里的问题呢?
作者: yidou    时间: 2006-07-03 13:52
原帖由 liuchang1881 于 2006-7-3 11:22 发表
在2410开发板上自己写了一个驱动程序,
我在用户空间read一个设备,在这个设备的read函数中用了wait_event_interruptible(wq,flags!=0);
当外部中断IRQ5发生时,在中断服务程序中执行flags=1;wake_up_interrupti ...


如果你确认是在wake_up_interruptible()死机,你可以把这个函数的内容直接拷过来,然后作些调试。我觉得可能是在wait_event_interruptible()死机

我以前遇到过类似的问题:
   flags=1;
    wake_up_interruptible
    wait_event_interruptible

调试后,发现flags变为0

[ 本帖最后由 yidou 于 2006-7-3 13:53 编辑 ]
作者: liuchang1881    时间: 2006-07-03 20:40
我的wake_up_interruptible是在中断响应函数中用到的,有中断时唤醒休眠的进程。可以看到函数有响应到中断,但并没有执行休眠的read操作,所以我觉得是在wake时死机的。
楼上的兄弟说wait_event_interruptible时死机是什么原因呢?
作者: richardhesidu    时间: 2006-07-03 21:38
锁有没有加对啊?还是没有加锁?
在read()函数中,在设置flag和进入休眠之间需要加个自旋锁吧。(这是我的猜测,最好吧这一部分代码贴出来,就比较容易分析了)。
作者: liuchang1881    时间: 2006-07-04 09:17
在read中
{u32 i;
  u16 *buff1;
  u32 *buff2;
  buff2=kmalloc(128,GFP_KERNEL);
  wait_event_interruptible(wq,flags!=0);
  ..............................
}

在中断处理函数中
{
  printk("interrupt 5 is working\n");
  flags=1;
  printk("flags is %d",flags);
  wake_up_interruptible(&wq);
}

我没有用到自选锁,不知道是不是有必要。现在中断中能输出flags is 1,可见是在wake时死机的。
作者: richardhesidu    时间: 2006-07-04 09:25
最好把read()函数和中断处理例程的代码都贴出来。
前面贴的那点代码透露的信息你前面都提到了。
作者: liuchang1881    时间: 2006-07-04 09:57
static void hpi_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/*hpi中断服务程序*/
{         
         printk("interrupt 5 is working\n";
         printk("HPI_BASE is %x\n",v_addr);
         outw(0x0005,&HPIC_W_L);
         outw(0x0005,&HPIC_W_H);
         printk("the data is %x and %x\n",HPIA_R_L,HPIA_R_H);
         printk("the data is %x and %x\n",HPIC_R_L,HPIC_R_H);
        //上面是一些初始化工作和测试输出
         flags=1;
         printk("flags is %d",flags);
         wake_up_interruptible(&wq);
}

static ssize_t hpi_read(struct file *file,char *buffer,size_t count,loff_t *ppos)
/*file_operation的“读”指针函数实现,为以后的read系统调用服务*/
{   
         u32 i;
         u32 *buff1;
         u32 *buff2;
         buff2=kmalloc(128,GFP_KERNEL);
         memset(buff2,0x66,12;
         buff1 = buff2;
         wait_event_interrutible(wq,flags!=0);

      if(flags)
      {       
       for(i=0;i<count/4;i++)
       {   
           u32 temp1,temp2;
           temp1 = HPID_R_F_L;
           temp2 = HPID_R_F_H;
           *buff1=temp1|(temp2<<16);
           printk("buff1 is %x\n",*buff1);
           buff1++;
       }
        if(verify_area(VERIFY_WRITE,buffer,count))
          {
              return -EFAULT;
              printk("buffer is not available";
          }
        if(copy_to_user(buffer,buff2,count)){
                retval=-EFAULT;
                goto out;
        }
          *ppos+=count;
         if(count>4)
           flags=0;
          retval = count;
          kfree(buff2);
        }
        
        else
          return 0;
       
   out:
          kfree(buff2);
          return retval;
          flags=0;
           
}

程序就是上面这些。
刚刚试了用动态的方法
wait_queue_head_t my_queue;
init_waitqueue_head (&my_queue);
代替static DECLARE_WAIT_QUEUE_HEAD(wq);
结果发生oops错误。不知是什么原因
作者: richardhesidu    时间: 2006-07-04 10:22
原帖由 liuchang1881 于 2006-7-4 09:57 发表
static void hpi_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/*hpi中断服务程序*/
{         
         printk("interrupt 5 is working\n");
         printk("HPI_BASE is %x ...


死机具体是什么时候?加载模块之后,还是调用hpi_read()之后?
你注册等待队列的地方在哪儿?模块的初始化函数中吗?
作者: liuchang1881    时间: 2006-07-04 10:40
死机是在应用程序中调用hpi_read()之后,可以休眠,但中断来时却不能唤醒,在wake时死机。
等待队列的是在驱动程序一开始的全局变量中注册的,不是在初始化函数中。
作者: liuchang1881    时间: 2006-07-04 10:51
我的qq是4599957,版主能不能加我一下啊?讨论起来更快些!
作者: snow_insky    时间: 2006-07-04 14:42
这个程序本身就存在很多问题,不死得难看,已经算你走运了。
一个最严重的问题就是read时内存的重复释放,以及内存泄漏。其次你不能一进来先等待,而是要先判断一下可不可读,如果不可读(flag == 0),才去等待。最好,给flag赋值时是需要锁定的,否则会产生竞争。

等解决了这些问题,如果还是死机的话,再来问吧!老兄,你不是在写应用程序,以你这样的编程习惯,你写内核程序,机子非要被重启折磨死不可。
作者: richardhesidu    时间: 2006-07-04 15:21
嗯,确实存在重复释放内存和内存的问题。搂主的c语言编程能力很有问题。
程序好像用了一个全局的变量在中断处理历程和read()函数之间传递值,这显然也是有问题的。
还有,最好用tasklet来处理中断的下半部。
作者: heavensword    时间: 2006-07-04 15:38
加锁保护

用interruptible_sleep_on(&ir_wq); 试试
spin_unlock_irqrestore(&priv->lock, flags);
interruptible_sleep_on(&ir_wq);
spin_lock_irqsave(&priv->lock, flags);

[ 本帖最后由 heavensword 于 2006-7-4 15:47 编辑 ]
作者: liuchang1881    时间: 2006-07-04 21:00
谢谢各位的指点,我以前是做硬件的,现在学着在硬件开发的基础上写一些底层的驱动,程序可能写的很乱,见笑了。
关于内存重复释放的问题,我觉得并不存在,因为每次系统调用read时先是开辟一块内存,处理完后在各个分支内释放。没有形成多次释放啊。以前没有采用进程休眠的时候,也没有引起系统混乱。
snow_insky 老兄说得方法我都试了,加了spin_lock()和spin_unlock()函数,还是在wake时死机。
版主所说的不用全局变量传递值,那又该如何传递呢?关于tasklet来处理中断的下半部的方法我再看看书。
我现在对驱动有了一些基本了解,正在学习阻塞读写,进程休眠和自选锁,信号量这块的知识,还要多多的向各位大侠学习!!!
作者: snow_insky    时间: 2006-07-05 09:15
你好好看看你的程序,不存在内存释放的问题?????
还有,你在单CPU系统中,用spin_lock就等于没用锁,因为这些函数都是空的,你应该要关中断。
作者: liuchang1881    时间: 2006-07-05 10:15
我再好好看看,关中断是什么意思呢?
我看的linux设备驱动(三版)中说单处理器在运行可抢占内核时是可以用spin_lock()的!?
作者: snow_insky    时间: 2006-07-05 12:54
用spin_lock_irq/spin_unlock_irq应该就可以了,你可以查找一下“内核同步机制”,它会告诉你内核同步一般有哪几种方式,这些方式都应用在什么场合。如果想要编写内核程序,这个是必须要理解的。
作者: liuchang1881    时间: 2006-07-06 18:34
我在上面的read()函数里加上信号量函数down_interruptible(sem),up(sem)和void init_MUTEX (struct semaphore *sem),想实现互斥锁的功能,结果出现Segmentation fault错误,是内存分配出现错误了吗?为什么不加down,up函数就没有这个错误呢?
作者: snow_insky    时间: 2006-07-06 18:36
用关本地中断的方式进行互斥,应该是最好的。
作者: liuchang1881    时间: 2006-07-06 19:07
非常感谢snow_insky老兄的全程指导!

可以说得详细一点吗?




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2