极客秀
搜索

linux设备驱动之waitqueue实现阻塞

当进程以阻塞的方式打开设备文件时(open默认的方式),如果资源不可用,那么进程阻塞,也就是进程进行休眠。
实际上就是如果进程发现资源不可用,那么它会主动的将资金的状态设置为TASK_UNINTERRUPTIBLE或者TASK_INTERRUPTIBLE,然后将资金加入到一个驱动所维护的等待队列中。
最后调用调度器schedule主动的释放CPU,操作系统将其从运行队列上移除,再调度其他的进行进行运行。这样做最大的好处就是,当资源不可用时,进程不占用CPU时间。
既然进程只是进行休眠,那么就应该存在唤醒的操作,否则进程将一直休眠。所以在驱动程序中,当资源可获取时,应该唤醒当前进程进行处理驱动事件。具体流程如下:

在Linux内核中,可通过等待队列在驱动程序中实现相应的阻塞操作。这就包括了进程的休眠和唤醒操作。Linux内核通过结构体struct
__wait_queue_head来描述一个等待队列,如下:



Linux内核中等待队列有如下操作:
1、定义初始化一个等待队列

2、 等待队列的基本操作

3、等待队列的interruptible操作
Interruptible表示进程在睡眠是可以通过信号来唤醒。也就是直接将当前进程设置为TASK_INTERRUPTIBLE状态,并且将其加入等待队列,然后让出调度,开始睡眠。即根据条件可以让进程进入休眠状态。

在默认情况下,唤醒操作将唤醒等待队列中所有的进程,但是如果一个进程时具有排他性的(也就是通过wait_event_interruptible_exclusive()接口加入等待队列的),那么唤醒操作在唤醒这个进程后就不会再唤醒其他进程了。
4、具有锁(locked)的等待队列操作

注:以上的所有接口的返回值如下:

  • 函数接口不带timeout时,那么返回0表示成功唤醒,返回-ERESTARTSYS表示被信号唤醒。

  • 函数接口带timeout时,返回0表示超时,返回大于0的值表示被成功唤醒,并且这个值表示离超时还剩余的时间。

通过以上介绍了关于等待队列实现阻塞的机制和函数接口,那么如何使用等待队列实现阻塞机制呢?
1、定义一个等待队列头,并将其初始化。
示例:

wait_queue_head_t wait_queue;

init_waitqueue_head(wait_queue)
2.定义一个状态标识,标识获得资源是否可用。
3.在struct file_operations函数操作集中与应用程序对应的接口(例如read())实现阻塞。
4.在中断中或者获取资源的接口中唤醒进程并标识当前资源可用。笔者在此通过按键中断的驱动程序来实现read()接口的阻塞操作。
头文件部分代码:waitqueue_driver.h

下面是源代码:waitqueue_driver.c

以下定义全局结构对象:

中断下半部处理程序:

中断上半部程序:

操作函数集接口:

操作函数集与硬件初始化:



驱动退出函数:

通过以上程序可实现按键的阻塞机制,在应用程序中,使用read即可读取应用程序状态,当没有按键按下时,Buttons_Method->key_state的取值为0,此时资源不可用。
在驱动button__read函数接口中的wait_event_interruptible(Buttons_Method->buttons_wq,Buttons_Method->key_state)处阻塞;
当按键按下时。Buttons_Method->key_state的值为非0,此时资源可用,进程被唤醒,跳出阻塞,然后将按键键值通过copy_to_user(buf,&event,count);传输到应用空间中,最后应用程序中的read读取到键值。应用程序代码如下:


总结:本文通过实例进行分析了通过等待队列wait queue在Linux内核驱动中实现阻塞机制,并详细分析了阻塞的原理和接口。


更多Linux教程请查看菜单

1.转载请保留原文链接谢谢!
2.本站所有资源文章出自互联网收集整理,本站不参与制作,如果侵犯了您的合法权益,请联系本站我们会及时删除。
3.本站发布资源来源于互联网,可能存在水印或者引流等信息,请用户擦亮眼睛自行鉴别,做一个有主见和判断力的用户。
4.本站资源仅供研究、学习交流之用,若使用商业用途,请购买正版授权,否则产生的一切后果将由下载用户自行承担。
5.联系方式(#替换成@):pm#vimge.com

  相关内容