Chinaunix首页 | 论坛 | 博客
  • 博客访问: 208493
  • 博文数量: 32
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 850
  • 用 户 组: 普通用户
  • 注册时间: 2013-11-22 15:50
文章存档

2014年(16)

2013年(16)

分类: 嵌入式

2014-01-07 22:05:54

                                  Linux设备驱动程序
                                  ——高级字符驱动程序操作(阻塞型I/O) 

    主要参考资料《Linux设备驱动程序》、tekkamanninja的博客 Linux设备驱动程序学习(5)-高级字符驱动程序操作[(2)阻塞型I/O和休眠] 和国嵌的实验手册、讲义视频等资料。
    当数据不可用时,用户可能调用read,或者进程试图写入数据,但因为输出缓冲区已满,设备还未准备好接收数据。调用进程通常不关心这类问题,程序员只会简单调用read和write,然后等待必要的工作结束后返回调用,在这种情况下,驱动程序应该阻塞该进程,将其置入休眠状态知道请求可继续。
一、休眠
    
当一个进程被置入休眠时,它会被标记为一种特殊状态并从调度器的运行队列中移走。直到某些状况下修改了这个状态,进程才会在任意CPU上调度,也即运行该进程,休眠中的进程会被搁置在一遍,等待将来的某个事件发生
    在Linux的驱动程序设计中,可以使用等待队列来实现进程的阻塞,等待队列就是一个进程链表,其中包含了等待某个特定事件的所有进程。在Linux中,一个等待队列通过一个“等待队列头(wait queue head)”来管理。在中定义了等待队列头结构体:
        struct __wait_queue_head {
            spinlock_t lock;
            struct list_head task_list;
        };
        typedef struct __wait_queue_head wait_queue_head_t;
    
    等待队列头的初始化:
    ① 静态方法:
        DECLARE_WAIT_QUEUE_HEAD(name);
    ② 动态方法:
        wait_queue_head_t my_queue;
        init_waitqueue_head(&my_queue);
二、简单休眠       
    当进程休眠时,它将期待某个条件会在未来成为真。Linux内核中最简单的休眠方式是称为wait_event的宏(以及它的几个变种):
        wait_event(wq, condition);                                /*不可中断休眠,不推荐*/
        wait_event_interruptible(wq, condition);                  /*推荐,返回非零值意味着休眠被中断,且驱动应返回 -ERESTARTSYS*/ 
        wait_event_timeout(wq, condition, timeout);
        wait_event_interruptible_timeout(wq, condition, timeout); /*有限的时间的休眠;若超时,则不管条件为何值返回0*/
    整个过程的另一半是唤醒。其他的某个线程(可能是另一个进程或者中断处理例程)必须为我们执行唤醒,因为我们的进程正在休眠中。用来唤醒休眠进程的基本函数式wake_up:
        void wake_up(wait_queue_head_t *queue);
        void wake_up_interruptible(wait_queue_head_t *queue);
三、阻塞和非阻塞型操作
阻塞方式:
    在阻塞型驱动程序中,Read实现方式如下:如果进程调用read,但设备没有数据或数据不足,进程阻塞。当新数据到达后,唤醒被阻塞进程。
    在阻塞型驱动程序中,Write实现方式如下:如果进程调用了write,但设备没有足够的空间供其写入数据,进程阻塞。当设备中的数据被读走后,缓冲区中空出部分空间,则唤醒进程。
非阻塞方式:
    阻塞方式是文件读写操作的默认方式,但应用程序员可通过使用O_NONBLOCK标志来人为的设置读写操作为非阻塞方式(该标志定义在中,在打开文件时指定)。如果设置了O_NONBLOCK标志,read和write的行为是不同的。如果进程在没有数据就绪时调用了read,或者在缓冲区没有空间时调用了write,系统只是简单地返回-EAGAIN,而不会阻塞进程。
四、一个阻塞I/O示例
    该示例来自国嵌:Blocking.rar
    
    进程app-read尝试读取数据时,不满足条件,进程被阻塞进入睡眠,另一进程app-write写入数据后,app-read进程条件满足被唤醒继续执行。
总结
    当一个设备无法立刻满足用户的读写请求时,驱动程序应当(缺省地)阻塞进程,使它进入睡眠,直到请求可以得到满足,这就是阻塞型字符驱动提出的原因。

阅读(2341) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~