阻塞的概念和接口使用
文件io模型:
1,非阻塞
2,阻塞
3,多路复用–select/poll
4, 异步信号通知faync
阻塞: 当进程在读取外部设备的资源(数据),资源没有准备好,进程就会休眠
linux应用中,大部分的函数接口都是阻塞
scanf();
read();
write();
accept();
驱动中需要调用
1,将当前进程加入到等待队列头中
add_wait_queue(wait_queue_head_t * q, wait_queue_t * wait)
2,将当前进程状态设置成TASK_INTERRUPTIBLE
set_current_state(TASK_INTERRUPTIBLE)
3,让出调度--休眠
schedule(void)
更加智能的接口,等同于上面的三个接口:
wait_event_interruptible(wq, condition)
驱动如何去写代码
1,等待队列头
wait_queue_head_t
init_waitqueue_head(wait_queue_head_t *q);
2,在需要等待(没有数据)的时候,进行休眠
wait_event_interruptible(wait_queue_head_t wq, condition) // 内部会构建一个等待队列项/节点wait_queue_t
参数1: 等待队列头
参数2: 条件,如果是为假,就会等待,如果为真,就不会等待
可以用一标志位,来表示是否有数据
3,在一个合适的时候(有数据),会将进程唤醒
wake_up_interruptible(wait_queue_head_t *q)
用法:
wake_up_interruptible(&key_dev->wq_head);
//同时设置标志位
key_dev->key_state = 1;
阻塞的实现——等待队列的使用
1.定义等待队列头并初始化
(init函数中)
2.在需要等待(没有数据)的时候,进行休眠
由于在init函数中调用了kzalloc,因此key_state=0
3.有数据需要去唤醒整个进程/等待队列
(key_irq_handler中断函数中)
非阻塞模式的实现
非阻塞: 在读写的时候,如果没有数据,立刻返回,并且返回一个出错码
用的会比较少,因为比较耗资源
open("/dev/key0", O_RDWR|O_NONBLOCK);
------------------------------------
驱动中需要去区分,当前模式是阻塞还是非阻塞
//如果当前是非阻塞模式,并且没有数据,立马返回一个出错码
if(filp->f_flags & O_NONBLOCK && !key_dev->key_state)
return -EAGAIN;
完整代码
key_driver.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/wait.h>
#include <linux/sched.h>
#define GPXCON_REG 0x11000C20
#define KEY_ENTER 28
//6.2.设计一个描述按键的数据的对象
struct key_event
{
int code;//表示按键的类型
int value;//表示按下还是抬起
};
//1.设定一个全局的设备对象
struct key_desc
{
unsigned int dev_major;
struct class *cls;
struct device *dev;
int irqno;
void *reg_base;
//按键
struct key_event event;
//7.1.定义等待队列头
wait_queue_head_t wq_head;
//7.3.表示是否有数据
int key_state;
};
struct key_desc *key_dev;
int get_irqno_from_node(void)
{
//4.1.1获取设备树中的节点
struct device_node *np = of_find_node_by_path("/key_int_node");
if (np)
{
printk("find node ok\n"