本帖最后由 penghubingzhou 于 2021-1-3 15:41 编辑
各位好,我是澎湖冰洲。元旦已经过去,还有一个多月时间就要过年了,考虑到各类因素(包括我的毕业论文以及学车问题等等因素),这一篇教程将是我在农历春节来临前的最后一更,年后我会恢复更新(这里也提前给各位拜个早年了~)
本来这一篇更新应该在元旦完成,但很可惜元旦那天我在火车上,于是乎只好把这篇留在今天发布了。上一节我们给各位讲了有关抽象类的知识,不知道各位有没有参悟吃透呢?如果没有吃透也没关系,可以在私下里找我,说实话我当初参悟IOKit抽象类这个事情也是花了不少时间完成的,不过参悟之后运用起来还是很自如的~
闲话少叙,让我们进入今天的内容——工作环(IOWorkloop)
啥是工作环呢?这个东西,乍一听上去挺高大上的。其实我当初学习工作环这块的东西时候,我也这么觉得。不过其实,工作环没这么神秘。
先让我们来看下苹果官方私货是怎么定义工作环的:
An IOWorkLoop object (or simply, a work loop) is primarily a gating mechanism that ensures single-threaded access to the data structures used by hardware. For some event contexts, a work loop is also a thread. In essence, a work loop is a mutually exclusive (mutex) lock associated with a thread. It does several things: Its gating mechanism synchronizes the actions among event sources. It provides a stackable environment for event handling. It spawns a dedicated thread for the completion of indirect interrupts delivered by the interrupt controller. This mechanism serializes interrupt handling for the work loop’s driver, preventing simultaneous access to driver data by multiple interrupts.
Emmmm……看着有点头疼?
没关系,我们慢慢分析。
在一个程序里,有时为了效率以及一些实际的需要,我们不得不让一个程序来同时做多件事。比如我们可能一边需要这个程序动态放映图片,然后同时还要在后台播放背景音乐,并且再同时下载一个文件,这种运行机制我们称之为并发执行。同样地,我们在驱动里,也会很经常地使用这类并发机制,其中最常见的一种就是中断(Interrupt)。举个例子,当我们正在使用我们的U盘复制文件时,此时因为某种原因(比如你的女盆友来找你出去吃饭了)我们不想复制了,于是我们点击取消按钮停止复制。假设这个时候没有中断机制,那么我们实现这个操作将是十分困难的事情,因为此时我们的驱动是非并发执行的,我们想要进行取消复制的操作,在不直接拔出来U盘的情况下,我们就必须等待U盘文件复制完成才能取消复制操作。听起来很蠢对不对?我们如果都已经复制完了文件,此时我们还需要取消复制干嘛?我们取消复制的目的就在于打断正常的复制过程,结果现在居然必须等到正常复制完成才能取消,那我们还取消干嘛呢?所以此时我们需要一种机制,来让计算机在运行过程中,出现某些意外情况需主机干预时,机器能自动停止正在运行的程序并转入处理新情况的程序,处理完毕后又返回原被暂停的程序继续运行。放到这个例子里,就是我们需要计算机及时响应我们的终止传输请求,停止文件的正常复制过程。这样的机制在计算机里,便是我们所述的中断。
显然,这样的一个过程也是一个并发的过程,在计算机的操作系统里,我们通常采用多线程来完成这样的一系列操作。在IOKit里,你也同样可以通过task_t这个多线程类型来开辟新的线程从而实现完成这样的一个操作。但是使用task_t会存在另一个问题:当不同的线程尝试访问同一个资源时,由于线程之间会相互竞争,它们之间对于数据的读写将可能破坏数据的完整性。比如对于一个驱动的线程A来说,它访问并写入了数据1,这个数据1目前存储的值是0x11,线程A向其中写入了0x1E这个值。此时,线程B又竞争读取数据1的内容,它期望读取的数据1的值应该是原有的0x11,但现在由于线程A重写了这块的数据为0x1E,不是原有的值了,这个时候线程B的执行就会失败。以上我举的例子还是一个最简单的例子,实际在驱动执行过程中,这样的错误是不能容忍的,小的会导致驱动执行失败,大的会直接导致驱动发生KP。尽管通过IOLock(IOKit提供的线程互斥锁,我们后面会进行详解)这个锁机制,我们可以实现对数据的锁定实现单线程访问,但声明一个锁是需要占用大量CPU时间的。实际的驱动执行过程中,我们的线程肯定要有好几条,如果每出现一个公共资源就声明一个锁,不仅会造成极大的资源浪费,也同样会拖慢系统的运行效率。由此,工作环诞生了。
为什么是工作环呢?简单来说,工作环是一个基于task_t以及IOLock的高级封装,它可以为你的各类事件源提供一个更加安全和可靠的线程环境,并提供对各类驱动数据的单线程安全访问。根据苹果官方私货的描述,工作环可以做到这么三件事:
1、提供选通机制,同步事件源之间的操作
2、为事件处理提供一个可堆叠的环境
3、生成单一专用线程完成间接中断,序列化处理保证数据线程安全。
通常来说,在IOKit里,如果你要做的并发任务是一些特殊的事件源处理任务,使用工作环将是一个更好的选择。
|