高级字符驱动程序操作之异步通知IO(理论篇)

本文介绍了如何通过设置进程为文件的属主,并启用FASYNC标志来实现异步通知机制,以此提高IO效率。但当多个文件同时发送信号时,仍需辅助手段明确信号来源。

1. 上一节我们已经学习了用poll轮询数据,来避免不必要的休眠,但是事实上,轮询的直接负面作用就是效率低下,这样一节我们学习如何使用异步通知IO来提高效率

 

2. fcntl系统调用

int fcntl(int fd, int cmd, long arg);

fcntl的作用是改变一个已打开文件的属性,fd是要改变的文件的描述符,cmd是命令罗列如下:

F_DUPFD, F_GETFD, F_SETFD, F_GETFL, F_SETFL, F_SETLK, F_SETLKW, F_GETLK, F_GETOWN, F_SETOWN

本节只关心F_SETOWN(设置异步IO所有权),F_GETFL(获取文件flags),F_SETFL(设置文件flags)

arg是要改变的属性内容

 

3. 用户进程启用异步通知机制

首先,设置一个进程作为一个文件的属主(owner),这样内核就知道该把文件的信号发送给哪个进程

fcntl(fd, F_SETOWN, getpid()); // getpid()就是当前进程咯

然后,给文件设置FASYNC标志,以启用异步通知机制

fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | FASYNC);

 

4. 缺陷

当有多个文件发送异步通知信号给一个进程时,进程无法知道是哪个文件发送的信号,这时候还是要借助poll的帮助完成IO

 

5. 从驱动程序的角度考虑

当文件的状态标志设置了FASYNC操作时,驱动程序会调用fasync的函数。

fasync的实现相当简单

static int scull_p_fasync(int fd, struct file *filp, int mode)

{

       struct scull_pipe *dev = filp->private_data;

       return fasync_helper(fd, filp, mode, &dev->async_queue);

}

 

当有新的数据到达时,驱动程序应该发送一个SIGIO给用户,这个操作用kill_fasync方法完成

if(dev->async_queue)

         kill_fasync(&dev->async_queue, SIGIO, POLL_IN);

 

最后,从异步通知列表中移除注册进去了的文件指针就直接调用scull_p_fasync(-1, filp, 0);

转载于:https://www.cnblogs.com/sankye/articles/2234661.html

### 华中科技大学操作系统课程中的字符设备驱动程序 在华中科技大学的操作系统课程材料中,字符设备驱动程序是指负责管理和控制计算机硬件资源的一类软件模块。这类驱动主要用于处理那些按顺序逐字节读写的设备,如键盘、鼠标以及串口等。 #### 字符设备驱动程序的特点 字符设备驱动程序具有以下特点[^1]: - **按需加载**: 设备驱动可以在需要时动态加载到内核空间。 - **同步/异步操作支持**: 支持阻塞模式下的同步调用和非阻塞模式下的异步调用。 - **多用户并发访问**: 能够允许多个进程同时打开同一个字符设备文件,并对其进行独立的操作。 #### 编写字符设备驱动的基本结构 编写Linux环境下的字符设备驱动主要包括以下几个方面: ##### 注册字符设备 ```c #include <linux/module.h> #include <linux/fs.h> static int major; static struct class *char_class; // 定义注册函数 static int __init char_driver_init(void){ // 动态分配主设备号 major = register_chrdev(0, "example_char", &fops); // 创建class对象以便于sysfs显示 char_class = class_create(THIS_MODULE, "example_char"); device_create(char_class, NULL, MKDEV(major, 0), NULL, "example"); printk(KERN_INFO "Example Char Driver Registered\n"); return 0; } ``` ##### 实现file_operations方法 为了使字符设备能够响应来自用户的IO请求,必须定义`struct file_operations`结构体来指定各种回调函数: ```c static ssize_t example_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos){ /* Read implementation */ } static ssize_t example_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos){ /* Write implementation */ } static long example_ioctl(struct file *filp, unsigned int cmd, unsigned long arg){ /* Ioctl implementation */ } static struct file_operations fops = { .owner = THIS_MODULE, .read = example_read, .write = example_write, .unlocked_ioctl = example_ioctl, }; ``` ##### 清理工作 当不再使用该字符设备时,应该注销对应的设备编号并释放所占用的内存和其他资源: ```c static void __exit char_driver_exit(void){ unregister_chrdev(major, "example_char"); device_destroy(char_class, MKDEV(major, 0)); class_unregister(char_class); class_destroy(char_class); printk(KERN_INFO "Example Char Driver Unregistered\n"); } module_init(char_driver_init); module_exit(char_driver_exit); MODULE_LICENSE("GPL"); ``` 上述代码展示了如何构建一个简单的字符设备驱动框架,其中包含了初始化、读取、写入、ioctl命令处理等功能。具体的逻辑可以根据实际应用场景进一步完善和发展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值