• linux驱动25:阻塞型I/O


    当数据不可用时,用户可能调用read,或缓冲区满了,用户调用write,在这些情况下,驱动程序应该阻塞该操作,将其置入休眠状态直到可以执行操作。

    休眠:当一个进程进入休眠状态,会被标记为一种特殊状态并从调度器运行队列移走。直到状态被修改,进程才被cpu调度。休眠的进程被搁置在一边,等待某个事件的发生。

    休眠的两条规则:一、永远不要在原子上下文中进入休眠;二、当一个休眠的进程被唤醒时,必须再次检查它所等待的条件是否的确为真。

    等待队列(简单休眠):

    等待队列就是一个进程链表,其中包括了等待某个特定事件的所有进程。在linux中,一个等待队列通过一个等待队列头来管理,类型为wait_queue_head_t,定义在<linux/wait.h>。

    初始化:

    init_waitqueue_head(wait_queue_head_t *);

    wait_event:

    在条件为真之前,进程保持休眠,休眠的同时,也检查进程等待的条件。

    wait_event(queue, condition)

    wait_event_interruptible(queue, condition)  可以被信号中断;可返回一个整数值,非零值表示休眠被信号中断

    wait_event_timeout(queue, condition, timeout)  等待给定的时间,超时返回0

    wait_event_interruptible_timeout(queue, condition, timeout)

    wake_up:

    void wake_up(queue)  唤醒等待在给定queue上的所有进程

    void wake_up_interruptible(queue)  只唤醒那些执行可中断休眠的进程

    使用wait_event时使用wake_up,使用wait_event_interruptible使用wake_up_interruptible

    1. #include <linux/init.h>
    2. #include <linux/module.h>
    3. #include <linux/moduleparam.h>
    4. #include <linux/kdev_t.h>
    5. #include <linux/fs.h>
    6. #include <linux/cdev.h>
    7. #include <linux/uaccess.h>
    8. #define MAX_BUF_LEN 256
    9. static int major = 277;
    10. static int minor = 0;
    11. static dev_t helloNum;
    12. struct class *helloClass = NULL;
    13. struct device *helloDev = NULL;
    14. wait_queue_head_t readWq, writeWq;
    15. static int haveData = 0;
    16. static char helloBuf[MAX_BUF_LEN] = {0};
    17. int hello_open(struct inode *pinode, struct file *pfile)
    18. {
    19. printk("hello_open, minor:%d, major:%d\n", iminor(pinode), imajor(pinode));
    20. return 0;
    21. }
    22. int hello_release(struct inode *pinode, struct file *pfile)
    23. {
    24. printk("hello_release, minor:%d, major:%d\n", iminor(pinode), imajor(pinode));
    25. return 0;
    26. }
    27. ssize_t hello_read(struct file *filep, char __user *buf, size_t size, loff_t *pos)
    28. {
    29. int copySize;
    30. if (size > MAX_BUF_LEN)
    31. {
    32. copySize = MAX_BUF_LEN;
    33. }
    34. else
    35. {
    36. copySize = size;
    37. }
    38. wait_event_interruptible(readWq, haveData == 1);
    39. if(copy_to_user(buf, helloBuf, copySize))
    40. {
    41. return -EFAULT;
    42. }
    43. printk("read:%s\n",helloBuf);
    44. haveData = 0;
    45. wake_up_interruptible(&writeWq);
    46. return copySize;
    47. }
    48. ssize_t hello_write(struct file *filep, const char __user *buf, size_t size, loff_t *pos)
    49. {
    50. int copySize;
    51. if(size > MAX_BUF_LEN)
    52. {
    53. copySize = MAX_BUF_LEN;
    54. }
    55. else
    56. {
    57. copySize = size;
    58. }
    59. wait_event_interruptible(writeWq, haveData == 0);
    60. memset(helloBuf, 0, MAX_BUF_LEN);
    61. if(copy_from_user(helloBuf, buf, copySize))
    62. {
    63. return -EFAULT;
    64. }
    65. printk("write:%s\n",helloBuf);
    66. haveData = 1;
    67. wake_up_interruptible(&readWq);
    68. return copySize;
    69. }
    70. static struct file_operations hello_ops = {
    71. .open = hello_open,
    72. .release = hello_release,
    73. .read = hello_read,
    74. .write = hello_write,
    75. };
    76. static int hello_init(void)
    77. {
    78. int ret = 0;
    79. printk("hello_init\n");
    80. ret = register_chrdev( major, "hello", &hello_ops);
    81. if(ret < 0)
    82. {
    83. printk("register_chrdev failed.\n");
    84. return ret;
    85. }
    86. helloClass = class_create(THIS_MODULE, "hellocls");
    87. if (IS_ERR(helloClass))
    88. {
    89. printk("class_create failed.\n");
    90. ret = PTR_ERR(helloClass);
    91. goto error_exit1;
    92. }
    93. helloNum = MKDEV(major,minor);
    94. printk("major:%d, minor:%d\n", MAJOR(helloNum), MINOR(helloNum));
    95. helloDev = device_create(helloClass, NULL, helloNum, NULL, "hello0");
    96. if (IS_ERR(helloDev))
    97. {
    98. printk("device_create failed.\n");
    99. ret = PTR_ERR(helloDev);
    100. goto error_exit2;
    101. }
    102. init_waitqueue_head(&readWq);
    103. init_waitqueue_head(&writeWq);
    104. return 0;
    105. error_exit2:
    106. class_destroy(helloClass);
    107. error_exit1:
    108. unregister_chrdev(major,"hello");
    109. return ret;
    110. }
    111. static void hello_exit(void)
    112. {
    113. printk("hello_exit\n");
    114. device_destroy(helloClass, helloNum);
    115. class_destroy(helloClass);
    116. unregister_chrdev(major,"hello");
    117. }
    118. MODULE_LICENSE("GPL");
    119. module_init(hello_init);
    120. module_exit(hello_exit);

  • 相关阅读:
    [书籍翻译]12周撰写期刊文章 学术出版成功指南——第 6 周:加强结构
    【数字信号去噪】粒子滤波器与FBS、MAP平滑方法数字信号去噪【含Matlab源码 2179期】
    Python爬虫——Urllib库-2
    面向对象【递归方法】
    报错:axios 发送的接口请求 404
    史上最强HashMap源码深度解析(3w字图文并茂)
    Oracle for Windows安装和配置——Oracle for Windows net配置
    Reactor模式
    VW ware安装Ubuntu虚拟机及环境配置
    Nodejs安装及其他事项
  • 原文地址:https://blog.csdn.net/dongyoubin/article/details/125467216