2019独角兽企业重金招聘Python工程师标准>>>

内核等待队列

等待队列

在linux驱动程序设计中,可以使用等待队列来实现进程的阻塞,等待队列可看作保存进程的容器,在阻塞进程时,将进程放入等待队列,当唤醒进程时,从等待队列中取出进程。

linux2.6内核提供了如下关于等待队列的操作:
1.定义等待队列

wait_queue_head_t  my_queue

2.初始化等待队列

init_waitqueue_head(&my_queue)

3.定义并初始化等待队列(直接代替第1、2两个操作)
DECLARE_WAIT_QUEUE_HEAD(my_queue)

4.有条件睡眠

——wait_event(queue, condition)

当condition(一个布尔表达式)为真时,立即返回;否则让进程进入TASK_UNINTERRUPTIBLE模式的睡眠,并挂载queue参数所指定的等待队列上

——wait_event_interruptible(queue, condition)

当condition(一个布尔表达式)为真时,立即返回;否则让进程进入TASK_INTERRUPTIBLE的睡眠,并挂载queue参数所指定的等待队列上

——int wait_event_killable(wait_queue_t queue, condition)

当condition(一个布尔表达式)为真时,立即返回;否则让进程进入TASK_KILLABLE的睡眠,并挂载queue参数所指定的等待队列上(TASK_UNINTERRUPTIBLE在中断和给它发送信号的时候都不会被唤醒;TASK_KILLABLE也如此,不过在发送kill信号的时候能被唤醒)

5.无条件睡眠(老版本,不建议使用)

——sleep_on(wait_queue_head_t *q)

让进程进入不可中断的睡眠,并把它放入等待队列q

——interruptible_sleep_on(wait_queue_head_t *q)

让进程进入可中断的睡眠,并把它放入等待队列q

6.从等待队列中唤醒进程

——wake_up(wait_queue _t *q)

从等待队列q中唤醒状态为TASK_UNINTERRUPTIBLE,TASK_INTERRUPTIBLE,TASK_KILLABLE的所有进程(唤醒:将进程从睡眠状态改为TASK_RUNNING状态,不过只是就绪状态而非执行态)

——wake_up_interruptible(wait_queue_t *q)

从等待队列q中唤醒状态为TASK_INTERRUPTIBLE的进程

阻塞型字符设备驱动

1、阻塞型字符设备驱动的功能 
      当一个设备无法立刻满足用户的读写请求时。例如:调用read时没有数据可读, 但以后可能会有;或者一个进程试图向设备写入数据,但是设备暂时没有准备好接收数据。应用程序通常不关心这种问题,应用程序只是调用 read 或 write 并得到返回值。驱动程序应当(缺省地)阻塞进程,使它进入睡眠,直到请求可以得到满足。 
2、阻塞方式 
      1)在阻塞型驱动程序中,Read实现方式如下:如果进程调用read,但设备没有数据或数据不足,进程阻塞。当新数据到达后,唤醒被阻塞进程。 
      2)在阻塞型驱动程序中,Write实现方式如下:如果进程调用了write,但设备没有足够的空间供其写入数据,进程阻塞。当设备中的数据被读走后,缓冲区中空出部分空间,则唤醒进程。 
3、非阻塞方式 
      阻塞方式是文件读写操作的默认方式,但应用程序员可通过使用O_NONBLOCK标志来人为的设置读写操作为非阻塞方式(该标志定义在<linux/fcntl.h>中,在打开文件时指定)。 
      如果设置了O_NONBLOCK标志,read和write的行为是不同的。如果进程在没有数据就绪时调用了read,或者在缓冲区没有空间时调用了write,系统只是简单地返回-EAGAIN,而不会阻塞进程。

例子

在.c中添加

bool have_data = false;

在头文件.h中添加 等待队列

读函数添加 检查是否有数据 并添加到等待队列

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; 
     
while (!have_data) /* 没有数据可读 ,考虑为什么不用if,而用while。因为wait_event_interruptible函数,除了收到数据会跳出外,中断也会跳出,中断唤醒等待队列,如果使用if就会往下运行但此时并没有数据可读会出错,故次用while和interruptible配合的原因 */

{

/*判断用户是否设置了非阻塞方式*/

if (filp->f_flags & O_NONBLOCK) 
            return -EAGAIN; /*设置了非阻塞方式*/ 
        /* 当设置了阻塞方式*/

wait_event_interruptible(dev->inq,have_data);/**当have_data为真时,立即返回,否则让进程进入TASK_KILL的睡眠 并挂在dev->inq队列上*/


  /*读数据到用户空间*/ 
  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\n", count, p); 
  } 
  
  have_data = false; /* 表明不再有数据可读 */ 
  return ret; 
}

写函数添加 有数据标志,并移出等待队列

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 (copy_from_user(dev->data + p, buf, count)) 
    ret =  - EFAULT; 
  else 
  { 
    *ppos += count; 
    ret = count; 
     
    printk(KERN_INFO "written %d bytes(s) from %d\n", count, p); 
  } 
  
  have_data = true; /* 有新的数据可读 */ 
     
    /* 唤醒读进程*/ 
    wake_up(&(dev->inq));

return ret; 
}

添加等待队列初始化函数

static int memdev_init(void) 

  int result; 
  int i;

dev_t devno = MKDEV(mem_major, 0);

/* 静态申请设备号*/ 
  if (mem_major) 
    result = register_chrdev_region(devno, 2, "memdev"); 
  else  /* 动态分配设备号 */ 
  { 
    result = alloc_chrdev_region(&devno, 0, 2, "memdev"); 
    mem_major = MAJOR(devno); 
  }   
  
  if (result < 0) 
    return result;

/*初始化cdev结构*/ 
  cdev_init(&cdev, &mem_fops); 
  cdev.owner = THIS_MODULE; 
  cdev.ops = &mem_fops; 
  
  /* 注册字符设备*/ 
  cdev_add(&cdev, MKDEV(mem_major, 0), MEMDEV_NR_DEVS); 
    
  /* 为设备描述结构分配内存*/ 
  mem_devp = kmalloc(MEMDEV_NR_DEVS * sizeof(struct mem_dev), GFP_KERNEL); 
  if (!mem_devp)    /*申请失败*/ 
  { 
    result =  - ENOMEM; 
    goto fail_malloc; 
  } 
  memset(mem_devp, 0, sizeof(struct mem_dev)); 
  
  /*为设备分配内存*/ 
  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); 
  
       /*初始化等待队列*/ 
     init_waitqueue_head(&(mem_devp[i].inq)); 
  } 
    
  return 0;

fail_malloc: 
  unregister_chrdev_region(devno, 1); 
  
  return result; 
}

测试函数

写函数

转载于:https://my.oschina.net/u/274829/blog/285758

linux 字符驱动阻塞型 等待队列相关推荐

  1. Linux 设备驱动--- 阻塞型字符设备驱动 --- O_NONBLOCK --- 非阻塞标志【转】

    阅读目录 1,以阻塞方式运行: 2,以非阻塞方式运行: 转自:http://blog.csdn.net/yikai2009/article/details/8653697 版权声明:本文为博主原创文章 ...

  2. Linux字符驱动开发学习总结

    linux驱动编写(虚拟字符设备编写) 昨天我们说了一些简单模块编写方法,但是终归没有涉及到设备的编写内容,今天我们就可以了解一下相关方面的内容,并且用一个实例来说明在linux上面设备是如何编写的. ...

  3. [Linux字符驱动] DIDO 74HC595实现遥控遥信功能

    项目中经常会使用YK和YX功能,DI操作,简单来说就是外部输入高电平,软件检测信号就为1:外部信号输入低电平,软件检测信号就为0:依据这样的设计,我们来看一下字符驱动该如何完成. 下面介绍一种有IO控 ...

  4. 嵌入式linux led驱动有几种写法,嵌入式Linux字符驱动LED灯设计

    一.任务要求 完成一个字符IO口驱动,在开发板上该IO口对应LED灯.该驱动程序通过控制IO口的高低电平来控制亮灭.同时要写一个应用层的测试程序,用来测试驱动程序.我的测试程序为myled_test. ...

  5. Linux字符驱动开发

    Linux字符驱动简介 字符设备驱动简介 举个栗子 file_operations 结构体 字符设备驱动开发步骤 驱动模块的加载和卸载 字符设备的注册和注销 添加 LICENSE 和作者信息 Linu ...

  6. 关于linux字符驱动中read函数filp->f_pos 和 loff_t *ppos的关系

    在学习linux 字符驱动的时候会有这样的困惑 比如我们实现一个字符驱动的读函数,如下 static ssize_t globalmem_read(struct file *filp, char __ ...

  7. linux 设备驱动阻塞,深入浅出:Linux设备驱动中的阻塞和非阻塞I/O

    今天写的是Linux设备驱动中的阻塞和非阻塞I/0,何谓阻塞与非阻塞I/O?简单来说就是对I/O操作的两种不同的方式,驱动程序可以灵活的支持用户空间对设备的这两种访问方式. 一.基本概念: 阻塞操作 ...

  8. linux字符驱动之点亮LED

    上一节中,我们讲解了如何自动创建设备节点,这一节我们在上一节的基础上,实现点亮LED. 上一节文章链接:https://blog.csdn.net/qq_37659294/article/detail ...

  9. Linux字符驱动设备开发

    一.基础知识 参考博客:18 linux字符设备驱动之设备号_jklinux的博客-CSDN博客 创建设备驱动的目的,通常是让用户程序来调用.一般我们使用字符设备文件来提供接口,使用户进程可以访问操作 ...

最新文章

  1. Flask中的重定向redirect和url_for
  2. Cell Research:华农解析水虻基因组图谱和肠道微生物组降解规律
  3. dataframe 按条件删行_根据列值删除Pandas中的DataFrame行
  4. Java Mocking入门—使用Mockito
  5. Python里三个最高逼格的调试神器
  6. 【Python】Pandas 数据类型概述与转换实战
  7. arm cortex-a8 天梯图_ARM正式推出CortexA78C核心:针对笔记本电脑设计、支持8个大核心...
  8. 微服务架构 —— 服务雪崩与容错方案
  9. Option键竟然如此强大,99.9%的Mac用户不知道的高效秘技
  10. linux集群应用实战(更新完毕)
  11. 1977年发生事件_大金蛇:千年银蛇,万年金蛇:1977年【蛇蛇人】11月上旬家里有“爆炸性”事件发生!...
  12. 能被3整除的Fibonacci的下标号
  13. 最好的磁盘管理工具Acronis Disk Director Suite 10.0英文原版 + 注册机 + 使用图文介绍
  14. python 源代码 macd双底 高 低_MACD双底,三底背离公式指标
  15. base scroll横向滚动_微信小程序实践:2.3 可滚动的容器组件之 scroll-view
  16. BootStrap3-基础入门
  17. 公用IPv6 IPv4 DNS
  18. LaTeX - 毕业答辩Beamer
  19. android手机小内存,世界最小Android手机问世 仅2.4英寸512MB内存
  20. python程序员面试自我介绍_「日语面试自我介绍」程序员日语自我介绍 - seo实验室...

热门文章

  1. php嵌套 frame,终极解决禁止网站被别人通过iframe引用嵌套套入。
  2. vb excel遍历列_EXCEL如何把多个表格合并成一个表格
  3. invalid signature 错误原因验签失败_Nginx 失败重试机制
  4. linux kvm usb设备,KVM usb passthrough配置
  5. 图解TCP四次握手断开连接
  6. 基于android的考勤定位算法,基于移动定位服务的考勤管理系统
  7. access开发精要(8)-设置行高、列宽、隐藏字段,取消隐藏字段,冻结列,取消冻结列,网格线
  8. python3精要(48)-os命令
  9. 适合小白的卷积神经网络图解
  10. 【Python】Python字典的高级用法-统计计数