请选择 进入手机版 | 继续访问电脑版

环信

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
热搜: mmap uikit gcc
查看: 304|回复: 3

6. 等待队列和设备阻塞方法

  [复制链接]

21

主题

43

帖子

140

积分

注册会员

Rank: 2

积分
140
发表于 2015-10-3 11:59:56 | 显示全部楼层 |阅读模式
本帖最后由 cat 于 2015-12-21 21:55 编辑

等待队列:
实现进程的阻塞,等待队列可看作保存进程的容器,在阻塞进程时,
将进程放入等待队列,当唤醒进程时,从等待等列中取出进程。

等待队列的操作:
1、定义等待队列
    wait_queue_head_t my_queue
2、初始化等待队列
    init_waitqueue_head(&my_queue)
3、定义并初始化等待队列
    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参数所指定的等待队列上。   
   
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 的所有进程。
wake_up_interruptible(wait_queue_t *q)
    从等待队列q中唤醒状态为TASK_INTERRUPTIBLE 的进程。  

memdev.c
  1. #include <linux/module.h>
  2. #include <linux/types.h>
  3. #include <linux/fs.h>
  4. #include <linux/errno.h>
  5. #include <linux/mm.h>
  6. #include <linux/sched.h>
  7. #include <linux/init.h>
  8. #include <linux/cdev.h>
  9. #include <asm/io.h>

  10. #include <linux/version.h>
  11. #if LINUX_VERSION_CODE > KERNEL_VERSION(3, 3, 0)
  12.         #include <asm/switch_to.h>
  13. #else
  14.         #include <asm/system.h>
  15. #endif
  16. #include <linux/slab.h>

  17. #include <asm/uaccess.h>

  18. #include "memdev.h"

  19. static int mem_major = MEMDEV_MAJOR;
  20. bool have_data = false; /*表明设备有足够数据可供读*/
  21. module_param(mem_major, int, S_IRUGO);
  22. struct mem_dev *mem_devp; /*设备结构体指针*/
  23. struct cdev cdev;

  24. /*文件打开函数*/
  25. int mem_open(struct inode *inode, struct file *filp)
  26. {
  27.     struct mem_dev *dev;
  28.    
  29.     /*获取次设备号*/
  30.     int num = MINOR(inode->i_rdev);

  31.     if (num >= MEMDEV_NR_DEVS)
  32.             return -ENODEV;
  33.     dev = &mem_devp[num];
  34.    
  35.     /*将设备描述结构指针赋值给文件私有数据指针*/
  36.     filp->private_data = dev;
  37.    
  38.     return 0;
  39. }

  40. /*文件释放函数*/
  41. int mem_release(struct inode *inode, struct file *filp)
  42. {
  43.     return 0;
  44. }

  45. /*读函数*/
  46. static ssize_t mem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
  47. {
  48.     unsigned long p =  *ppos;
  49.     unsigned int count = size;
  50.     int ret = 0;
  51.     struct mem_dev *dev = filp->private_data; /*获得设备结构体指针*/

  52.     /*判断读位置是否有效*/
  53.     if (p >= MEMDEV_SIZE)
  54.         return 0;
  55.     if (count > MEMDEV_SIZE - p)
  56.         count = MEMDEV_SIZE - p;
  57.    
  58.     while (!have_data)
  59.     /*
  60.     没有数据可读,考虑为什么不用if,而用while,中断信号唤醒
  61.     -->>>使用了wait_event_interruptible,中断可以唤醒阻塞,但没有数据,所以要重覆检测,用while
  62.     -->>>使用了wait_event,就不需要while作重覆的判断。
  63.     */
  64.     {
  65.         /*
  66.         调用read时没有数据可读, 但以后可能会有;或者一个进程试图向设备写入数据,但是设备暂时没有准备好接收数据。
  67.         应用程序通常不关心这种问题,应用程序只是调用read 或write 并得到返回值。驱动程序应当(缺省地)阻塞进程,
  68.         使它进入睡眠,直到请求可以得到满足。

  69.         如果设置了O_NONBLOCK标志,read和write的行为是不同的。如果进程在没有数据就绪时调用了read,或者在缓冲
  70.              区没有空间时调用了write,系统只是简单地返回-EAGAIN,而不会阻塞进程
  71.         */
  72.             if (filp->f_flags & O_NONBLOCK)
  73.                 return -EAGAIN;
  74.             /*
  75.             在阻塞型驱动程序中,Read实现方式如下:如果进程调用read,但设备没有数据或数据不足,进程阻塞。
  76.             当新数据到达后,唤醒被阻塞进程。在阻塞型驱动程序中,Write实现方式如下:
  77.         如果进程调用了write,但设备没有足够的空间供其写入数据,进程阻塞。当设备中的数据被读走后,
  78.         缓冲区中空出部分空间,则唤醒进程。
  79.             */
  80.         
  81.         wait_event_interruptible(dev->inq,have_data);
  82.     }


  83.     /*读数据到用户空间*/
  84.     if (copy_to_user(buf, (void*)(dev->data + p), count))
  85.     {
  86.         ret =  - EFAULT;
  87.     }
  88.     else
  89.     {
  90.         *ppos += count;
  91.         ret = count;

  92.         printk(KERN_INFO "read %d bytes(s) from %d\n", count, p);
  93.     }

  94.     have_data = false; /* 表明不再有数据可读 */
  95.     return ret;
  96. }

  97. /*写函数*/
  98. static ssize_t mem_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
  99. {
  100.     unsigned long p =  *ppos;
  101.     unsigned int count = size;
  102.     int ret = 0;
  103.     struct mem_dev *dev = filp->private_data; /*获得设备结构体指针*/

  104.     /*分析和获取有效的写长度*/
  105.     if (p >= MEMDEV_SIZE)
  106.         return 0;
  107.     if (count > MEMDEV_SIZE - p)
  108.         count = MEMDEV_SIZE - p;

  109.     /*从用户空间写入数据*/
  110.     if (copy_from_user(dev->data + p, buf, count))
  111.         ret =  - EFAULT;
  112.     else
  113.     {
  114.         *ppos += count;
  115.         ret = count;

  116.         printk(KERN_INFO "written %d bytes(s) from %d\n", count, p);
  117.     }

  118.     have_data = true; /* 有新的数据可读 */

  119.     /* 唤醒读进程 */
  120.     wake_up(&(dev->inq));

  121.     return ret;
  122. }

  123. /* seek文件定位函数 */
  124. static loff_t mem_llseek(struct file *filp, loff_t offset, int whence)
  125. {
  126.     loff_t newpos;

  127.     switch(whence) {
  128.       case 0: /* SEEK_SET */
  129.         newpos = offset;
  130.         break;

  131.       case 1: /* SEEK_CUR */
  132.         newpos = filp->f_pos + offset;
  133.         break;

  134.       case 2: /* SEEK_END */
  135.         newpos = MEMDEV_SIZE -1 + offset;
  136.         break;

  137.       default: /* can't happen */
  138.         return -EINVAL;
  139.     }
  140.     if ((newpos<0) || (newpos>MEMDEV_SIZE))
  141.         return -EINVAL;
  142.         
  143.     filp->f_pos = newpos;
  144.     return newpos;

  145. }

  146. /*文件操作结构体*/
  147. static const struct file_operations mem_fops =
  148. {
  149.     .owner = THIS_MODULE,
  150.     .llseek = mem_llseek,
  151.     .read = mem_read,
  152.     .write = mem_write,
  153.     .open = mem_open,
  154.     .release = mem_release,
  155. };

  156. /*设备驱动模块加载函数*/
  157. static int memdev_init(void)
  158. {
  159.     int result;
  160.     int i;

  161.     dev_t devno = MKDEV(mem_major, 0);

  162.     /* 静态申请设备号*/
  163.     if (mem_major)
  164.         result = register_chrdev_region(devno, 2, "memdev");
  165.     else  /* 动态分配设备号 */
  166.     {
  167.         result = alloc_chrdev_region(&devno, 0, 2, "memdev");
  168.         mem_major = MAJOR(devno);
  169.     }  

  170.     if (result < 0)
  171.         return result;

  172.     /*初始化cdev结构*/
  173.     cdev_init(&cdev, &mem_fops);
  174.     cdev.owner = THIS_MODULE;
  175.     cdev.ops = &mem_fops;

  176.     /* 注册字符设备 */
  177.     cdev_add(&cdev, MKDEV(mem_major, 0), MEMDEV_NR_DEVS);

  178.     /* 为设备描述结构分配内存*/
  179.     mem_devp = kmalloc(MEMDEV_NR_DEVS * sizeof(struct mem_dev), GFP_KERNEL);
  180.     if (!mem_devp)    /*申请失败*/
  181.     {
  182.         result =  - ENOMEM;
  183.         goto fail_malloc;
  184.     }
  185.     memset(mem_devp, 0, sizeof(struct mem_dev));

  186.     /*为设备分配内存*/
  187.     for (i=0; i < MEMDEV_NR_DEVS; i++)
  188.     {
  189.         mem_devp[i].size = MEMDEV_SIZE;
  190.         mem_devp[i].data = kmalloc(MEMDEV_SIZE, GFP_KERNEL);
  191.         memset(mem_devp[i].data, 0, MEMDEV_SIZE);

  192.         //2、初始化等待队列
  193.         init_waitqueue_head(&(mem_devp[i].inq));
  194.     }

  195.     return 0;

  196.     fail_malloc:
  197.     unregister_chrdev_region(devno, 1);

  198.     return result;
  199. }

  200. /*模块卸载函数*/
  201. static void memdev_exit(void)
  202. {
  203.     cdev_del(&cdev);   /*注销设备*/
  204.     kfree(mem_devp);     /*释放设备结构体内存*/
  205.     unregister_chrdev_region(MKDEV(mem_major, 0), 2); /*释放设备号*/
  206. }

  207. MODULE_AUTHOR("Dick Tsang");
  208. MODULE_LICENSE("GPL");

  209. module_init(memdev_init);
  210. module_exit(memdev_exit);
复制代码


回复

使用道具 举报

21

主题

43

帖子

140

积分

注册会员

Rank: 2

积分
140
 楼主| 发表于 2015-12-21 17:41:38 | 显示全部楼层
memdev.h

  1. #ifndef _MEMDEV_H_
  2. #define _MEMDEV_H_

  3. #ifndef MEMDEV_MAJOR
  4. #define MEMDEV_MAJOR 261   /*预设的mem的主设备号*/
  5. #endif

  6. #ifndef MEMDEV_NR_DEVS
  7. #define MEMDEV_NR_DEVS 2    /*设备数*/
  8. #endif

  9. #ifndef MEMDEV_SIZE
  10. #define MEMDEV_SIZE 4096
  11. #endif

  12. /*mem设备描述结构体*/
  13. struct mem_dev                                    
  14. {                                                        
  15.         char *data;                     
  16.         unsigned long size;
  17.         wait_queue_head_t inq;   //1、定义等待队列   
  18. };

  19. #endif /* _MEMDEV_H_ */
复制代码
回复 支持 反对

使用道具 举报

21

主题

43

帖子

140

积分

注册会员

Rank: 2

积分
140
 楼主| 发表于 2015-12-21 17:42:02 | 显示全部楼层
app-read.c
  1. #include <stdio.h>

  2. int main()
  3. {
  4.         FILE *fp = NULL;
  5.         char Buf[128];
  6.        
  7.         /*初始化Buf*/
  8.         strcpy(Buf,"memdev is char dev!");
  9.         printf("BUF: %s\n",Buf);
  10.        
  11.         /*打开设备文件*/
  12.         fp = fopen("/dev/memdev0","r+");
  13.         if (fp == NULL)
  14.         {
  15.                 printf("Open memdev0 Error!\n");
  16.                 return -1;
  17.         }
  18.        
  19.         /*清除Buf*/
  20.         strcpy(Buf,"Buf is NULL!");
  21.         printf("Read BUF1: %s\n",Buf);
  22.        
  23.         /*读出数据*/
  24.         fread(Buf, sizeof(Buf), 1, fp);
  25.        
  26.         /*检测结果*/
  27.         printf("Read BUF2: %s\n",Buf);
  28.        
  29.         fclose(fp);
  30.        
  31.         return 0;       

  32. }
复制代码
回复 支持 反对

使用道具 举报

21

主题

43

帖子

140

积分

注册会员

Rank: 2

积分
140
 楼主| 发表于 2015-12-21 17:42:23 | 显示全部楼层
app-write.c
  1. #include <stdio.h>

  2. int main()
  3. {
  4.         FILE *fp = NULL;
  5.         char Buf[128];
  6.        
  7.        
  8.         /*打开设备文件*/
  9.         fp = fopen("/dev/memdev0","r+");
  10.         if (fp == NULL)
  11.         {
  12.                 printf("Open Dev memdev0 Error!\n");
  13.                 return -1;
  14.         }
  15.        
  16.         /*写入设备*/
  17.         strcpy(Buf,"memdev is char dev!");
  18.         printf("Write BUF: %s\n",Buf);
  19.         fwrite(Buf, sizeof(Buf), 1, fp);
  20.        
  21.         sleep(5);
  22.         fclose(fp);
  23.        
  24.         return 0;       

  25. }
复制代码
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|环信 Glofty.com ( 粤ICP备15084637号 )

GMT+8, 2017-1-23 04:19 , Processed in 0.221923 second(s), 21 queries .

快速回复 返回顶部 返回列表