《linux设备驱动开发详解》中支持阻塞操作的globalfifo设备驱动
来源:互联网 发布:淘宝卖家手机端装修 编辑:程序博客网 时间:2024/05/29 10:59
一些概念
阻塞操作:执行设备操作时,若不能获得资源,挂起进程(进入睡眠状态)直到满足可操作的条件后再进行操作。
非阻塞操作:执行设备操作时,若不能获得资源,要么放弃、要么不停查询。
代码解析
- 基于上文”《linux设备驱动开发详解》中globalmem代码笔记“的代码,只是将globalmem中的全局内存(devp所指)变成FIFO,并将globalmem重命名为”globalfifo”
- 当FIFO中有数据的时候,读进程才能把数据读出,且读取后的数据要从FIFO移除;当FIFO不是满的时候,写进程才能往FIFO中写数据
- 实现功能:读FIFO进程将唤醒写FIFO进程,写FIFO也将唤醒FIFO的进程
- 结构体的更改
struct globalfifo_dev{ struct cdev cdev; unsigned int current_len;//FIFO中数据长度 unsigned char mem[GLOBALFIFO_SIZE]; struct mutex mutex; /***************************************** *增加两个等待队列头部,分别对应读和写 *******************************************/ wait_queue_head_t r_wait; wait_queue_head_t w_wait;};struct globalfifo_dev *globalfifo_devp;
注:等待队列一般来实现阻塞进程的唤醒。
5. 加载函数XXX_init
static int __init globalfifo_init(void){ //allocate dev_t ... //init mutex ... /*************************************** *初始化“等待队列头部” ***************************************/ init_waitqueue_head(&globalfifo_devp->r_wait); init_waitqueue_head(&globalfifo_devp->w_wait); //register cdev ...}module_init(globalfifo_init);
注:
“等待队列头部”与“等待队列元素”:“等待队列元素”是要添加到“等待队列头部”实现之后的唤醒
6. 读函数read: 读函数中需要唤醒写进程
static ssize_t globalfifo_read(struct file *filp, char __user *buff, size_t size, loff_t *ppos){ unsigned int count = size; int ret = 0; struct globalfifo_dev *dev = filp->private_data; /***************************************************** *定义并初始化“等待队列元素”wait ******************************************************/ DECLARE_WAITQUEUE(wait, current); mutex_lock(&dev->mutex); /*************************************************** *将“等待队列元素”添加到“等待队列头元素”,此时并未休眠 ***************************************************/ add_wait_queue(&dev->r_wait, &wait); while (dev->current_len == 0){ /************************************************* *若是设置成非阻塞模式则直接跳出循环,避免阻塞 ************************************************* if (filp->f_flags & O_NONBLOCK){ ret = -EAGAIN; goto out; } /************************************** *标记浅度睡眠标志,并未睡眠 *****************************************/ __set_current_state(TASK_INTERRUPTIBLE); /*************************************** *!!!!!!!重要:睡眠前,要释放锁 ***************************************/ mutex_unlock(&dev->mutex); /************************************ *睡眠 ************************************/ schedule(); /*********************************** *浅睡眠有可能是被信号唤醒,而我们只需要写进程唤醒我们,所以需要判断是不是信号唤醒 ***********************************/ if (signal_pending(current)){ ret = -ERESTARTSYS; goto out2; } mutex_lock(&dev->mutex);//不是信号唤醒,访问资源前需要加锁 } if (count > dev->current_len) count = dev->current_len; if (copy_to_user(buff, dev->mem, count)){ ret = -EFAULT; goto out; }else{ memcpy(dev->mem, dev->mem+count, dev->current_len - count);//读完之后需要将未读数据往前挪 dev->current_len -= count;//已读的count字节的数据空出来了 printk(KERN_INFO"read %d bytes, current_len: %d\n", count, dev->current_len); /********************************************** *唤醒写进程 ********************************************** wake_up_interruptible(&dev->w_wait); ret = count; }out: mutex_unlock(&dev->mutex);out2: remove_wait_queue(&dev->w_wait, &wait);//将“等待队列元素”从“头部”删除 set_current_state(TASK_RUNNING);//设置成就绪状态 return ret;}
7.写函数write
与读函数差不多
static ssize_t globalfifo_write(struct file *filp, const char __user *buff, size_t size, loff_t *ppos){ unsigned int count = size; int ret; struct globalfifo_dev *dev = filp->private_data; DECLARE_WAITQUEUE(wait, current);// mutex_lock(&dev->mutex); add_wait_queue(&dev->w_wait, &wait);// while(dev->current_len == GLOBALFIFO_SIZE){ if (filp->f_flags & O_NONBLOCK){ ret = -EAGAIN; goto out; } __set_current_state(TASK_INTERRUPTIBLE);// mutex_unlock(&dev->mutex); schedule();// if (signal_pending(current)){ ret = -ERESTARTSYS; goto out2; } mutex_lock(&dev->mutex); } if (count > GLOBALFIFO_SIZE - dev->current_len)//整个FIFO大小 减去 有效数据大小 count = GLOBALFIFO_SIZE - dev->current_len; if (copy_from_user(dev->mem+dev->current_len, buff, count)){ ret = -EFAULT; goto out; }else { dev->current_len += count; printk(KERN_INFO"written %d bytes, current_len:%d\n", count, dev->current_len); wake_up_interruptible(&dev->r_wait); ret = count; }out: mutex_unlock(&dev->mutex);out2: remove_wait_queue(&dev->w_wait, &wait); set_current_state(TASK_RUNNING); return ret;}
注:
等待队列的模板
static ssize_t XXX_write(struct file *filp, const char __user *buff, size_t size, loff_t *ppos){ ... DECLARE_WAITQUEUE(wait, current);//定义等待队列元素 add_wait_queue(&dev->w_wait, &wait);//添加等待元素到队列 /*等待设备缓冲区可写*/ do{ avail = device_writable(...); if (avail < 0) { if (filp->f_flags & O_NONBLOCK){//阻塞 ret = -EAGAIN; goto out; } } __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态 schedule();//调度其他进程 if (signal_pending(current)){//判断是否信号唤醒 ret = -ERESTARTSYS; goto out2; } }while(avail<0); device_write()//写数据out: remove_wait_queue(&XXX_wait, &wait); set_current_state(TASK_RUNNING); return ret;}
阅读全文
0 0
- 《linux设备驱动开发详解》中支持阻塞操作的globalfifo设备驱动
- 8--2支持阻塞操作的globalfifo设备驱动
- 《Linux设备驱动开发详解》源码——globalfifo
- 支持阻塞操作的字符设备驱动
- Hasen的linux设备驱动开发学习之旅--支持阻塞的设备驱动
- linux设备驱动开发学习之旅--支持阻塞的设备驱动
- Hasen的linux设备驱动开发学习之旅--支持轮询操作的设备驱动
- linux设备驱动开发学习之旅--支持轮询操作的设备驱动
- linux设备驱动开发-设备阻塞访问的简单实现
- 《Linux4.0设备驱动开发详解》笔记--第八章:linux设备驱动的阻塞与非阻塞
- 《Linux设备驱动开发详解》-- 原子操作
- 设备驱动中的阻塞与非阻塞I/O----globalfifo驱动
- Hasen的linux设备驱动开发学习之旅--支持多设备的字符设备驱动
- Linux设备驱动开发详解
- LINUX设备驱动开发详解
- linux设备驱动开发详解
- linux设备驱动开发学习之旅--支持多设备的字符设备驱动
- Linux设备驱动开发详解-Note(16)---Linux 设备驱动中的阻塞与非阻塞 I/O(1)
- 乘法逆元数论篇
- Deeplearning.ai学习笔记之第一课第一周
- Linux下创建svn以及相关操作
- linux下自创网络编程聊天室(4)改进两点
- 数论--几何--笛卡尔原理
- 《linux设备驱动开发详解》中支持阻塞操作的globalfifo设备驱动
- C++中std::stringstream类型对象如何清除
- 51nod 1050 循环数组最大子段和
- HTTP Cookie
- 汇编语言入门四:打通C和汇编语言
- 添加一个页面覆盖
- 8月19日TMS开发笔记
- 组合数取模(0)
- Csharp进阶:非泛型集合