• 网站刚刚上线,难免有不足的地方,敬请谅解!欢迎提出宝贵意见!

  •    3年前 (2015-07-31)  专业技术 内核驱动 |   5 条评论  130 
    文章评分 1 次,平均分 5.0

    我们之前介绍过简单的read,write操作,那么会有一个问题:当驱动无法立即响应请求该怎么办?比如一个进程调用read读取数据,当没有数据可读时该怎么办,是立即返回还是等到有数据的时候;另一种情况是进程调用write向设备写数据,如果缓冲区满了或者设备正忙的时候怎么办,是立即返回还是继续等待直到设备可写?这种情况下,一般的缺省做法是使进程睡眠直到请求可以满足为止。本篇就介绍遇到这类问题驱动的处理方法。

    睡眠

    什么是睡眠?一个进程睡眠意味着它暂时放弃了CPU的运行权,直到某个条件发生后才可再次被系统调度。

    在驱动里面很容易使一个进程进入睡眠状态,但是这里有几个规则需要特别注意。

    1. 原子上下文不能睡眠。这意味着驱动在持有一个自旋锁, seqlock, 或者 RCU 锁时不能睡眠。
    2. 关闭中断的情况下不能睡眠。在中断处理函数中不能睡眠。
    3. 在持有信号量时可以睡眠,但是会造成其他等待的进程也会进入睡眠,所以应该特别注意,睡眠时间应很短。
    4. 在被唤醒后应做一些必要的检查,确定你等待的条件已经满足。因为你不知道睡眠的这段时间发生了什么。
    5. 睡眠前确定能被唤醒,否则不要睡眠。

    如何睡眠和唤醒

    睡眠的进程会进入等待队列,一个等待队列可以如下声明:

    DECLARE_WAIT_QUEUE_HEAD(name);
    或者动态地, 如下:

    wait_queue_head_t my_queue;
    init_waitqueue_head(&my_queue);

    当一个进程需要睡眠,可以调用下面的接口:

    要唤醒休眠的进程,那么其他的进程要调用唤醒函数:

    阻塞和非阻塞的选择

    上面说了睡眠的方法,这种实现就是阻塞IO的实现,还有一种情况是要求不管IO是否可用,调用都要立即返回,就是非阻塞的实现。比如read时,虽然没有数据可读,但是我不想等待,我要立马返回。

    非阻塞的IO由 filp->f_flags 中的 O_NONBLOCK 标志来指示,这个标志位于<linux/fcntl.h>, 被 <linux/fs.h>自动包含。这个标志可以在open的时候指定。

    缺省状态下IO是阻塞的(没有指定O_NONBLOCK的情况下),在实现read/write的时候需要符合下面的标准:

    • 如果一个进程调用 read 但是没有数据可用(尚未), 这个进程必须阻塞. 这个进程在有数据达到时被立刻唤醒, 并且那个数据被返回给调用者, 即便小于在给方法的 count 参数中请求的数量。
    • 如果一个进程调用 write 并且在缓冲中没有空间, 这个进程必须阻塞, 并且它必须在一个与用作 read 的不同的等待队列中. 当一些数据被写入硬件设备, 并且在输出缓冲中的空间变空闲, 这个进程被唤醒并且写调用成功, 尽管数据可能只被部分写入如果在缓冲只没有空间给被请求的 count 字节。

    这两句话都假设有输入和输出缓冲,实际上也是这样,几乎每个设备驱动都有输入输出缓冲。缓冲提高了访问效率,防止了数据的丢失。

    如果指定O_NONBLOCK,即非阻塞的访问。read和write的做法是不同的。在这种情况下,这些调用简单的返回-EAGAIN。只有read,write和open文件操作收到非阻塞标志的影响。

    下面是一个简单的read的实现,其中兼容了阻塞和非阻塞的实现(关键地方以添加注释):

    互斥等待

    之前我们说过当一个进程调用wake_up后,所有这个队列上等待的进程被置为可运行的。一般情况下这样是没有问题的,但是在个别的情况下,可能提前知道只有一个被唤醒的进程将成功获得需要的资源,并且其他的进程将再次睡眠。如果等待的进程太多,全部唤醒在进入睡眠这样的操作也是耗费资源的,会降低系统的性能。为了应对这种情况,内核中添加了一个互斥等待的选项。这样的结果是,进行互斥等待的进程被一次唤醒一个。

    互斥等待一般情况下用不到,所以不再关注。

    这篇就暂时说到这里,下一篇继续看其他的一些高级字符驱动操作poll/select等。

    之前系列文章如下,欢迎阅读关注:

    Linux设备驱动第一篇:设备驱动程序简介

    Linux设备驱动第二篇:构造和运行模块

    Linux设备驱动第三篇:写一个简单的字符设备驱动

    Linux设备驱动第四篇:以Oops信息定位代码行为例谈驱动调试方法

    Linux设备驱动第五篇:驱动中的并发与竟态

    Linux设备驱动第六篇:高级字符驱动操作之Iotcl

    本文属原创,转载请注明出处,违者必究

    关注微信公众平台:程序员互动联盟(coder_online),你可以第一时间获取原创技术文章,和(java/C/C++/Android/Windows/Linux)技术大牛做朋友,在线交流编程经验,获取编程基础知识,解决编程问题。程序员互动联盟,开发人员自己的家。

    Linux设备驱动第七篇:高级字符驱动操作之阻塞IO

     

    本文原始地址:http://www.coderonline.net/linux-device-driver-seventh-advanced-character-driven-action-blocking-io.html

    本站所有文章,除特别注明外,均为本站原创,转载请注明出处来自http://www.coderonline.net/

    否则保留追究法律责任的权利!

    发表评论

    表情 格式
    1. 给个赞先

      ghost045 评论达人 LV.5 3年前 (2015-07-31) [0] [0]
    2. :smile:

      Anny 评论达人 LV.3 3年前 (2015-07-31) [1] [0]
    1. 2017-01-05下午3:57
      venuspoor.com[ 来自 火星 ]

      venuspoor.com

      Linux设备驱动第七篇:高级字符驱动操作之阻塞IO – 程序员互动联盟

    2. 2016-12-29上午8:34
      http://whilelimitless.com/limitless-pill/is-it-real/[ 来自 火星 ]

      http://whilelimitless.com/limitless-pill/is-it-real/

      Linux设备驱动第七篇:高级字符驱动操作之阻塞IO – 程序员互动联盟

    3. 2016-11-29下午1:49
      http://www.valras-plage.net/xl-trigger/[ 来自 火星 ]

      http://www.valras-plage.net/xl-trigger/

      Linux设备驱动第七篇:高级字符驱动操作之阻塞IO – 程序员互动联盟

    切换注册

    登录

    忘记密码 ?

    切换登录

    注册