Linux驱动总结3
if(_IOC_NR(cmd)> ioarg = &mem_devp-> wait-> spin_lock_irqsave(&q-> if (list_empty(&wait-> spin_unlock_irqrestore(&q-> spin_lock_irqsave(&q-> spin_unlock_irqrestore(&q-> list_for_each_entry_safe(curr, next, &q-> unsigned flags = curr-> if (curr-> _t wrqueue; }; 2、然后在模块初始化中初始化队列头: /*初始化函数*/ static int memdev_init(void) { .... for(i = 0; i < MEMDEV_NR_DEVS; i) { mem_devp[i].size = MEMDEV_SIZE; /*对设备的数据空间分配空间*/ mem_devp[i].data = kmalloc(MEMDEV_SIZE,GFP_KERNEL); /*问题,没有进行错误的控制*/ memset(mem_devp[i].data,0,MEMDEV_SIZE); /*初始化定义的互信息量*/ //初始化定义的自旋锁ua spin_lock_init(&(mem_devp[i].lock)); /*初始化两个等待队列头,需要注意必须用括号包含起来,使得优先级正确*/ init_waitqueue_head(&(mem_devp[i].rdqueue)); init_waitqueue_head(&(mem_devp[i].wrqueue)); } ... } 3、确定一个具体的条件,比如数据有无,具体的条件根据实际的情况设计。 /*等待条件*/ static bool havedata = false; 4、在需要堵塞的读函数,写函数中分别实现堵塞,首先定义等待队列的节点,并添加到队列中去,然后等待事件的唤醒进程。但是由于读写操作的两个等待队列都是基于条件havedata的,所以在读完成以后需要唤醒写,写完成以后需要唤醒读操作,同时更新条件havedata,最后还要移除添加的等待队列节点。 /*read函数的实现*/ static ssize_t mem_read(struct file *filp,char __user *buf, size_t size,loff_t *ppos) { unsigned long p = *ppos; unsigned int count = size; int ret = 0; struct mem_dev *dev = filp->private_data; /*参数的检查,首先判断文件位置*/ if(p >= MEMDEV_SIZE) return 0; /*改正文件大小*/ if(count > MEMDEV_SIZE - p) count = MEMDEV_SIZE - p; #if 0 /*添加一个等待队列节点到当前进程中*/ DECLARE_WAITQUEUE(wait_r,current); /*将节点添加到等待队列中*/ add_wait_queue(&dev->rdqueue,&wait_r); /*添加等待队列,本来采用if即可,但是由于信号等可能导致等待队列的唤醒,因此采用循环,确保不会出现误判*/ #endif while(!havedata) { /*判断用户是否设置为非堵塞模式读,告诉用户再读*/ if(filp->f_flags & O_NONBLOCK) return -EAGAIN; /*依据条件havedata判断队列的状态,防止进程被信号唤醒*/ wait_event_interruptible(dev->rdqueue,havedata); } spin_lock(&dev->lock); /*从内核读数据到用户空间,实质就通过private_data访问设备*/ if(copy_to_user(buf,(void *)(dev->data p),count)) { /*出错误*/ ret = -EFAULT; } else { /*移动当前文件光标的位置*/ *ppos = count; ret = count; printk(KERN_INFO "read %d bytes(s) from %d",count,p); } spin_unlock(&dev->lock); #if 0 /*将等待队列节点从读等待队列中移除*/ remove_wait_queue(&dev->rdqueue,&wait_r); #endif /*更新条件havedate*/ havedata = false; /*唤醒写等待队列*/ wake_up_interruptible(&dev->wrqueue); return ret; } /*write函数的实现*/ static ssize_t mem_write(struct file *filp,const char __user *buf,size_t size,loff_t *ppos) { unsigned long p = *ppos; unsigned int count = size; int ret = 0; /*获得设备结构体的指针*/ struct mem_dev *dev = filp->private_data; /*检查参数的长度*/ if(p >= MEMDEV_SIZE) return 0; if(count > MEMDEV_SIZE - p) count = MEMDEV_SIZE - p; #if 0 /*定义并初始化一个等待队列节点,添加到当前进程中*/ DECLARE_WAITQUEUE(wait_w,current); /*将等待队列节点添加到等待队列中*/ add_wait_queue(&dev->wrqueue,&wait_w); #endif /*添加写堵塞判断*/ /*为何采用循环是为了防止信号等其他原因导致唤醒*/ while(havedata) { /*如果是以非堵塞方式*/ if(filp->f_flags & O_NONBLOCK) return -EAGAIN; /*分析源码发现,wait_event_interruptible 中存在DECLARE_WAITQUE
Linux驱动总 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)