1.阻塞与非阻塞I/O介绍

阻塞和非阻塞I/O是设备访问的两种不同模式。阻塞操作是指在执行设备操作时,若不能获得资源,则挂起进程直到满足可操作的条件后再进行操作。被挂起的进程进入睡眠状态,被从调度器的运行队列移走,直到等待的条件被满足。而非阻塞操作的进程在不能进行设备操作时,并不挂起,它要么放弃,要么不停地查询,直至可以进行操作为止。

驱动程序通常需要提供这样的能力:当应用程序进行read()、write()等系统调用时,若设备的资源不能获取,而用户又希望以阻塞的方式访问设备,驱动程序应在设备驱动的xxx_read()、xxx_write()等操作中将进程阻塞直到资源可以获取,此后,应用程序的read()、write()等调用才返回,整个过程仍然进行了正确的设备访问,用户并没有感知到;若用户以非阻塞的方式访问设备文件,则当设备资源不可获取时,设备驱动的xxx_read()、xxx_write()等操作应立即返回,read()、write()等系统调用也随即被返回,应用程序收到-EAGAIN返回值。

2.阻塞进程的唤醒

在Linux驱动程序中,可以使用等待队列(Wait Queue)来实现阻塞进程的唤醒。等待队列很早就作为一个基本的功能单位出现在Linux内核里了,它以队列为基础数据结构,与进程调度机制紧密结合,可以用来同步对系统资源的访问。

wait_queue_head_t my_queue;   //定义“等待队列头部”,wait_queue_head_t是__wait_queue_head结构体的一个typedef

init_waitqueue_head(&my_queue); //初始化“等待队列头部”

DECLARE_WAIT_QUEUE_HEAD (name);   //此宏可以作为定义并初始化等待队列头部的“快捷方式”

DECLARE_WAITQUEUE(name, tsk);  //定义等待队列元素,定义并初始化一个名为name的等待队列元素。

/*添加和移除等待队列*/

void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);//将等待队列元素wait添加到等待队列头部q指向的双向链表中

void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);//将等待队列元素wait从由q头部指向的链表中移除

/*等待事件*/

wait_event(queue, condition)
wait_event_interruptible(queue, condition)
wait_event_timeout(queue, condition, timeout)

wait_event_interruptible_timeout(queue, condition, timeout)

等待第1个参数queue作为等待队列头部的队列被唤醒,而且第2个参数condition必须满足,否则继续阻塞。wait_event()和wait_event_interruptible()的区别在于后者可以被信号打断,而前者不能。加上_timeout后的宏意味着阻塞等待的超时时间,以jiffy为单位,在第3个参数的timeout到达时,不论condition是否满足,均返回。

/*唤醒队列*/

void wake_up(wait_queue_head_t *queue);

void wake_up_interruptible(wait_queue_head_t *queue);

wake_up()应该与wait_event()或wait_event_timeout()成对使用,而wake_up_interruptible()则应与wait_event_interruptible()或wait_event_interruptible_timeout()成对使用。wake_up()可唤醒处于TASK_INTERRUPTIBLE和TASK_UNINTERRUPTIBLE的进程,而wake_up_interruptible()只能唤醒处于TASK_INTERRUPTIBLE的进程

/*在等待队列上睡眠*/

sleep_on(wait_queue_head_t *q );

interruptible_sleep_on(wait_queue_head_t *q );

sleep_on()函数的作用就是将目前进程的状态置成TASK_UNINTERRUPTIBLE,并定义一个等待队列元素,之后把它挂到等待队列头部q指向的双向链表,直到资源可获得,q队列指向链接的进程被唤醒。interruptible_sleep_on()与sleep_on()函数类似,其作用是将目前进程的状态置成TASK_INTERRUPTIBLE,并定义一个等待队列元素,之后把它附属到q指向的队列,直到资源可获得(q指引的等待队列被唤醒)或者进程收到信号。

sleep_on()函数应该与wake_up()成对使用,interruptible_sleep_on()应该与wake_up_interruptible()成对使用。

/* 示例  */

static int __init globalfifo_init(void)
{
 int ret;
 dev_t devno = MKDEV(globalfifo_major, 0);

if (globalfifo_major)
 ret = register_chrdev_region(devno, 1, "globalfifo");
 else {
 ret = alloc_chrdev_region(&devno, 0, 1, "globalfifo");
 globalfifo_major = MAJOR(devno);
 }
 if (ret < 0)
 return ret;

globalfifo_devp = kzalloc(sizeof(struct globalfifo_dev), GFP_KERNEL);
 if (!globalfifo_devp) {
 ret = -ENOMEM;
 goto fail_malloc;
 }

globalfifo_setup_cdev(globalfifo_devp, 0);

mutex_init(&globalfifo_devp->mutex);
init_waitqueue_head(&globalfifo_devp->r_wait);
init_waitqueue_head(&globalfifo_devp->w_wait);

return 0;

fail_malloc:
unregister_chrdev_region(devno, 1);
return ret;
}
module_init(globalfifo_init);

linux设备驱动学习(四)——阻塞与非阻塞I/O相关推荐

  1. linux设备驱动学习,linux设备驱动学习4

    Linux设备驱动程序学习(4) -高级字符驱动程序操作[(1)ioctl and llseek] 今天进入<Linux设备驱动程序(第3版)>第六章高级字符驱动程序操作的学习. 一.io ...

  2. linux设备驱动学习笔记(1)

    学习了将近半个月的设备驱动程序的编写,也有一些体会,这里写下来也给学习做一个总结,为后面的学习做更好的准备. 首先,个人感觉驱动程序的设计是很有套路的,最基本的要求就是要掌握这些套路.所谓的套路就是一 ...

  3. linux设备驱动学习(二)——字符设备编写及测试

    一.字符设备体结构介绍 1.字符设备作为linux内核三大驱动设备之一,主要完成字节的读写操作,常见的应用有鼠标.键盘等,结构体形式如下所示: struct cdev{ struct kobject ...

  4. linux 设备驱动学习总结

    从熟悉的开始. 设备驱动模型. device device driver class bus dra7xx pcie驱动 bus:platform bus device:platform_device ...

  5. linux设备驱动学习(三)——并发控制

    1.并发介绍 一般来说,操作系统都是支持并发执行能力的,多个执行单元访问同一个模块时,如果不能支持并发,则会让这个模块功能紊乱,像读写操作时.两个用户同时读写,那么可能一个用户执行读操作时,另一个用户 ...

  6. linux设备驱动学习(一)——简单的helloworld模块

    在内核驱动中新建hello文件夹 1.需要.c文件与Makefile文件 在..../drivers/hello目录下新建xxx.c 和Makefile文件 .c文件样例: #include < ...

  7. linux mdev 命令,linux设备驱动----利用mdev(udev)自动创建设备文件节点

    1.mdev的使用方法和原理: mdev是busybox 自带的一个简化版的udev,适合于嵌入式的应用埸合.其具有使用简单的特点.它的作用,就是在系统启动和热插拔或动态加载驱动程序时,自动产生驱动程 ...

  8. Linux 设备驱动中的 I/O模型(一)—— 阻塞和非阻塞I/O

    在前面学习网络编程时,曾经学过I/O模型 Linux 系统应用编程--网络编程(I/O模型),下面学习一下I/O模型在设备驱动中的应用. 回顾一下在Unix/Linux下共有五种I/O模型,分别是: ...

  9. linux 设备驱动阻塞,深入浅出:Linux设备驱动中的阻塞和非阻塞I/O

    今天写的是Linux设备驱动中的阻塞和非阻塞I/0,何谓阻塞与非阻塞I/O?简单来说就是对I/O操作的两种不同的方式,驱动程序可以灵活的支持用户空间对设备的这两种访问方式. 一.基本概念: 阻塞操作 ...

最新文章

  1. Typora添加右键新建Markdown文件
  2. Android 打包混肴
  3. 基于BootstarbTable实现加载更多的方式
  4. 从难以普及的数据增强技术,看AI的性价比时代
  5. 重装JDK后Tomcat和Eclipse的配置
  6. 初识Nginx服务器
  7. mongodb 搜索速度_初识 MongoDB 数据库
  8. 解决Ubuntu下切换到root用户后没有声音问题
  9. spring boot 如何动态替换bean?
  10. linux-目录结构
  11. lr 中cookie的解释与用法
  12. 阅读下面程序,请回答如下问题:
  13. 福州英华职业学院计算机专业在哪个校区,福州英华职业学院五年制大专地址在哪里...
  14. 让前辈再次激励我不断进步
  15. 小米电视es65、ea65、ex65和ec65区别
  16. html表格边框默认值,table表格边框的设置
  17. 服务器五大相关基础知识【转】
  18. python ez setup.py_python 安装 ez_setup.py出现的问题及解决办法
  19. ExaGrid入围2021年存储大奖
  20. 高数中dy和Δy有什么区别

热门文章

  1. python文件读写_python基础-文件读写'r' 和 'rb'区别
  2. matlab 里的mod,matlab中mod()函数究竟有什么用?具体的作用(不要告诉我怎么算,我只想知道他有什么用)...
  3. 昇思MindSpore年终盘点 | 看完这篇正式开启虎年!
  4. 基于知识图谱的问答系统(以医疗行业为例)
  5. 还在为DST模型刷不动而感到苦恼吗?来试试无监督DST吧,DSI等你来战!
  6. CVPR 2019 | STGAN: 人脸高精度属性编辑模型
  7. 招聘 | 香侬在召唤:算法工程师,让金融把你的代码变现
  8. AOGNet:基于深度 AND-OR 语法网络的目标识别方法 | PaperDaily #28
  9. Python中操作MySQL/Oracle
  10. 深度神经网络中处理数据和训练模型的一些技巧