18 设备处理内核I/O包

Posted xuan01

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了18 设备处理内核I/O包相关的知识,希望对你有一定的参考价值。

I/O包:

内核要求设备完成的任务,需要调用驱动程序,传参给驱动;操作所需的参数数量大,需要 I/O 包 统一管理;

objnode_t 结构:objnode_t 结构包含了各个驱动程序功能函数的所有参数;

创建和删除 I/O 包:

内存管理组件分配释放objnode_t结构;krlnew_objnode 创建,krldel_objnode 删除;

向设备发送I/O包:

krldev_io 发送设备io函数:接受objnode_t 结构参数,检查操作码是否符合要求,检查被操作的对象是不是为空,然后调用krldev_call_driver 函数;

krldev_call_driver 函数 还要进行一次检查,然后用操作码为索引调用驱动程序功能;

驱动程序实例之 systick 设备驱动:

systick 设备:每隔1ms产生一个中断;定时器功能;

systick设备驱动程序的整体框架:

驱动程序必须具备的一系列函数,即使不做任何工作,只返回状态,也必须有这个函数;

systick 设备驱动程序的入口;

systick_entry 入口函数,实现建立设备,向内核注册设备,安装回调函数,并且初始化 用到的8254中断物理设备;最后调用krlenable_intline 函数,主要功能是开启一个中断源的中断;

接着把入口函数放到驱动表里;

配置设备与驱动:

systick_set_driver 函数:设置驱动程序功能派发函数(就是将驱动函数的地址设置到driver_t 的drv_dipfun数组,io操作码就是此数组索引),设置驱动程序名称;

systick_set_device 函数:设置设备的信息;设备类型是很重要的,内核通过这个区分设备;此函数的第一个参数就是device_t 结构指针;

打开与关闭设备:

systick_open 函数:简单实现一个增加计数功能;

systick_close 函数:实现减小计数;

systick设备中断回调函数:

对于systick设备,重要的是这个函数,周期性的执行系统中的操作;

systick_handle 函数:中断要实现的功能;这儿只是简单的打印消息;

 

实验效果后续更新(4.30):

此处实验,之前我们在每个进程中都要主动调用进程调度器函数,否则进程就会永远霸占 CPU,永远运行下去。这是因为,我们没有定时器可以周期性地检查进程运行了多长时间,如果进程的运行时间超过了,就应该强制调度,让别的进程开始运行;这儿我们在 systick_handle 函数中调用krlthd_inc_tick函数,每20ms强制调度:

 

010 异步I/O处理 003

 异步I/0
  ○ 使用设备内核对象
  ○ 使用事件内核对象 提醒同步以及交互
  ○ 可提醒I/O 不可跨线程的
  ○ I/O完成端口

 

  ⊙ I/O完成端口

    ○ 串行模型来进行异步IO操作
    ○ 并行模型 -> 多线程

    ○ 1个工人 -> 加工零件 -> 5天 -> 串行
    ○ 5个工人 -> 加工零件 -> 1天 -> 并行

    ○ 单核 -> 模拟出来的多进程 线程
    ○ 多核 -> 多线程 核心数 -> CPU的一个核心
    ○ 一个进程内可以有多个线程 多线程
    ○ 线程和线程之间可以相互融合

  ⊙ I/O完成端口 天生就是并行模式

    ○ 并行模型 -> 多线程

    ○ 创建队列
      ○ 设备
      ○ 设备

    ○ 设备操作的队列

      ○ 线程池
      ○ 多个线程

    ○ 创建一个完成端口

1     HANDLE hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, 0);

● CreateIoCompletionPort 函数
1 HANDLE WINAPI CreateIoCompletionPort(
2   _In_     HANDLE    FileHandle,                        //内核对象
3   _In_opt_ HANDLE    ExistingCompletionPort,        //已存在的完成端口 为NULL 则位新建一个IOCP
4   _In_     ULONG_PTR CompletionKey,                    //传递处理函数的参数
5   _In_     DWORD     NumberOfConcurrentThreads        //设置线程数 尽量根据物理实际设置
6 );

● PostQueuedCompletionStatus
1 BOOL WINAPI PostQueuedCompletionStatus(
2   _In_     HANDLE       CompletionPort,                    //指定想向其发送一个完成数据包的完成端口对象
3   _In_     DWORD        dwNumberOfBytesTransferred,        //指定—个值,直接传递给GetQueuedCompletionStatus函数中对应的参数
4   _In_     ULONG_PTR    dwCompletionKey,                //指定—个值,直接传递给GetQueuedCompletionStatus函数中对应的参数
5   _In_opt_ LPOVERLAPPED lpOverlapped                    //指定—个值,直接传递给GetQueuedCompletionStatus函数中对应的参数
6 );

● GetQueuedCompletionStatus
BOOL WINAPI GetQueuedCompletionStatus(
  _In_  HANDLE       CompletionPort,                //指定想向其发送一个完成数据包的完成端口对象
  _Out_ LPDWORD      lpNumberOfBytes,            //一次完成后的I/O操作所传送数据的字节数。
  _Out_ PULONG_PTR   lpCompletionKey,            //当文件I/O操作完成后,用于存放与之关联的CK。
  _Out_ LPOVERLAPPED *lpOverlapped,            //OVERLAPPED  结构体指针
  _In_  DWORD        dwMilliseconds                //用于指定调用者等待CP的时间。
);

 



以上是关于18 设备处理内核I/O包的主要内容,如果未能解决你的问题,请参考以下文章

010 异步I/O处理 002

进程通过内核缓存区请求设备I/O的一些事情

010 异步I/O处理 003

I/O模型

《Linux内核设计与实现》读书笔记(十四)- 块I/O层

(笔记)Linux内核学习之I/O层和I/O调度机制