在windows操作系统内核中,首先要明白四个概念,apc(异步过程调用),dpc(延迟过程调用),irp(io请求包)以及基于优先级的抢占式调度,下面分别解释:
1.apc。 异步过程调用类似于linux下的信号,只不过信号处理函数的执行需要两步:设置和触发,而apc则只有一步,只需要将apc回调函数排入线程的apc对 列,它就总会被执行的。apc对列对于每个线程有两个,一个是用户空间的apc对列,一个是内核空间的apc对列,apc函数运行在apc优先级上,它一 般高于用户线程的优先级。
2.dpc。延迟过程调用一般用于中断的后期处理。中断可在任何进程(线程)的上下文里面运行,而且一般情况下中断处理 函数要关闭相应中断,以防重入,为了使这种不确定的情况时间最小化,windows只会在中断处理函数里面呆一小会,然后排队一个dpc,从而退出中断,dpc在低于isr的优先级运行,因此它可被硬件中断中断。
3.irp。这在windows里是一个异常重要的概念,它直接导致 windows的设计理念和类unix以及unix的设计理念的不同。一个irp封装了一个io操作过程,它的内部是一个栈结构,每个栈帧代表一个驱动程 序模块,其中封装了此驱动的回调函数,irp就是一级一级往下层驱动传递从而完成一个io操作。
4.基于优先级的抢占式调度。这个是 windows下的调度策略,它完全基于优先级(还有时间片,但不影响什么,时间片对所有进程的策略一样),而不是其它。如果有更高优先级线程就绪,那么它将马上抢占当前线程。就连中断都有自己优先级,呵呵,当然它是最高的...windows的响应性依赖于动态优先级提升,但是这就牵扯到别的方面了,和这篇文章的主题不对,因此不讨论。
明白了上面的概念以后,我们就可以继续了。
windows的io操作步骤如下:
1.应用程序调用ReadFile函数
2.ntdll.dll将用户请求陷入内核空间继续处理,由io管理器接管
3.io管理器创建一个irp,然后根据用户请求填充其字段,接着将其交给最上层驱动程序
4.驱动程序一层一层将irp传给硬件设备后一层层返回。注意,每往下传递一层都要注册io完成回调。
到这里,如果是异步调用,那么就可以返回用户空间处理了,如果是同步的,则在io管理器那里被阻塞,io操作还没有完,接着往下看:
5.硬件操作完成,产生中断,中断排队一个dpc后返回
6.dpc运行,调用驱动的完成例程
7.每层的完成例程相继被调用,控制流一层层的返回给io管理器
8.将ReadFileEx中的用户apc排队(异步情况下),这个apc将在不长的时间内被调用,因为它的优先级高于用户线程。
以 上就是windows的io流程,可见,irp的自洽性与独立性使得一切成为可能,irp包含了足够的信息足以使io操作脱离线程环境,这也是 windows内核整体的设计理念----模块化。windows的优先级控制非常巧妙,有个概念叫“中断请求级”,就是将cpu的运行分成了不同的级别分别为:PASSIVE_LEVEL---DISPATCH_LEVEL---PROFILE_LEVEL,windows将任务在这几个优先级中分配, 使得操作变得简单,它基于一条原则:一旦某CPU执行在高于PASSIVE_LEVEL的IRQL上时,该CPU上的活动仅能被拥有更高IRQL的活动抢先。这条原则保证了很多操作可以安全进行,比如io派遣例程运行在PASSIVE_LEVEL上,而从irp对列拽一个irp以求处理的dpc运行在DISPATCH_LEVEL,这样就不会有任何派遣例程打扰一个irp的操作,从而省去了锁的操作,在一个硬件中断中,运行在硬件中断优先级的cpu将一个dpc排入该cpu对列,中断完毕后cpu降至DISPATCH_LEVEL优先级,dpc得以执行...优先级控制正是windows的一大特色。
综上我们明白了windows异步io的几大要素:1.独立自洽的irp结构;2.优先级的控制。进一步抽象到了windows的设计思想:模块化。windows本身是微内核系统,而微内核就是模块化的。
反观linux的异步io,其实现就是在原来同步阻塞点直接返回,然后在以后重试,负责重试的在老内核不支持异步io的情况下是一系列用户线程,而在 2.6以后是工作队列,而工作队列本质上是一个内核线程,由此可见,linux中并没有和windows对应的dpc的概念,如果非要拉出来一个长得像的,那就是softirq了,但是也就仅仅执行点像,实际上softirq在大多数情况下是由softirqd内核线程执行的,为的就是不让 softirq(dpc?)长期占据处理器,试想一个多网卡的高负载的服务器,softirq几乎占据了很大一块cpu资源,于是乎,不管什么,不管你多 特殊,一律统一接收线程调度程序的调度,这就是公平。而在windows中却显得不那么公平,当然也可以在windows驱动里面自觉地建立内核线程,但是那毕竟不是系统提供的功能啊!
linux和unix一脉相承,简单,公平,统一可能就是它们的品质,一切都是文件,一切接受调度,接口统一;windows相比就显得有些花花绿绿了, 但我还是很欣赏它的优先级控制方案。传统unix本质上是同步的,因为它简单,受控性很好,可预测,所以它稳定,如果在内核一个函数阻塞了,进程不能继续了,unix的做法就是直接调度schedule,而windows的做法就是异步唤醒,然后调整优先级之类的,因为它本质就是异步的。linux最近吸取了unix和windows的优点,所以直接调度和异步唤醒在内核均可见到,不错不错,但是有些乱,变化太快,我很担心如果linux没有一个根本是设 计理念,随着它复杂性增加,代码膨胀,它会不会失控?!
内核稳定性和它们的设计理念有关吗?仅说一点,windows是基于优先级的,dpc在DISPATCH_LEVEL 运行,除了硬中断用户进程无法将它抢占,那么如果它在内核睡眠的话.....而linux一视同仁,内核线程和用户线程统一被调度,当然就不会频繁挂机了....这仅仅从线程化软中断角度讲,实际上linux下的softirq也是不能睡眠的,因为你不能保证每个softirq都在内核线程上下文执行,不过这并不是问题,现在的新内核都将中断给线程化了,还有什么做不到呢?windows的中断请求优先级实际上是一种抽象,将实际执行硬件或软件和执行本身分离,这是非常不错的,简简单单的一个优先级提升或降低加上一个基本原则就可以代替linux的一大堆加锁解锁禁用抢占之操作。
不管是linux还是windows,其本身都运用了统一,简单的思想,只不过用的地方不同,linux提供的vfs,尽量线程化,windows的优先级控制,对象化.....
windows和linux不愧是两大巨猛系统
1.apc。 异步过程调用类似于linux下的信号,只不过信号处理函数的执行需要两步:设置和触发,而apc则只有一步,只需要将apc回调函数排入线程的apc对 列,它就总会被执行的。apc对列对于每个线程有两个,一个是用户空间的apc对列,一个是内核空间的apc对列,apc函数运行在apc优先级上,它一 般高于用户线程的优先级。
2.dpc。延迟过程调用一般用于中断的后期处理。中断可在任何进程(线程)的上下文里面运行,而且一般情况下中断处理 函数要关闭相应中断,以防重入,为了使这种不确定的情况时间最小化,windows只会在中断处理函数里面呆一小会,然后排队一个dpc,从而退出中断,dpc在低于isr的优先级运行,因此它可被硬件中断中断。
3.irp。这在windows里是一个异常重要的概念,它直接导致 windows的设计理念和类unix以及unix的设计理念的不同。一个irp封装了一个io操作过程,它的内部是一个栈结构,每个栈帧代表一个驱动程 序模块,其中封装了此驱动的回调函数,irp就是一级一级往下层驱动传递从而完成一个io操作。
4.基于优先级的抢占式调度。这个是 windows下的调度策略,它完全基于优先级(还有时间片,但不影响什么,时间片对所有进程的策略一样),而不是其它。如果有更高优先级线程就绪,那么它将马上抢占当前线程。就连中断都有自己优先级,呵呵,当然它是最高的...windows的响应性依赖于动态优先级提升,但是这就牵扯到别的方面了,和这篇文章的主题不对,因此不讨论。
明白了上面的概念以后,我们就可以继续了。
windows的io操作步骤如下:
1.应用程序调用ReadFile函数
2.ntdll.dll将用户请求陷入内核空间继续处理,由io管理器接管
3.io管理器创建一个irp,然后根据用户请求填充其字段,接着将其交给最上层驱动程序
4.驱动程序一层一层将irp传给硬件设备后一层层返回。注意,每往下传递一层都要注册io完成回调。
到这里,如果是异步调用,那么就可以返回用户空间处理了,如果是同步的,则在io管理器那里被阻塞,io操作还没有完,接着往下看:
5.硬件操作完成,产生中断,中断排队一个dpc后返回
6.dpc运行,调用驱动的完成例程
7.每层的完成例程相继被调用,控制流一层层的返回给io管理器
8.将ReadFileEx中的用户apc排队(异步情况下),这个apc将在不长的时间内被调用,因为它的优先级高于用户线程。
以 上就是windows的io流程,可见,irp的自洽性与独立性使得一切成为可能,irp包含了足够的信息足以使io操作脱离线程环境,这也是 windows内核整体的设计理念----模块化。windows的优先级控制非常巧妙,有个概念叫“中断请求级”,就是将cpu的运行分成了不同的级别分别为:PASSIVE_LEVEL---DISPATCH_LEVEL---PROFILE_LEVEL,windows将任务在这几个优先级中分配, 使得操作变得简单,它基于一条原则:一旦某CPU执行在高于PASSIVE_LEVEL的IRQL上时,该CPU上的活动仅能被拥有更高IRQL的活动抢先。这条原则保证了很多操作可以安全进行,比如io派遣例程运行在PASSIVE_LEVEL上,而从irp对列拽一个irp以求处理的dpc运行在DISPATCH_LEVEL,这样就不会有任何派遣例程打扰一个irp的操作,从而省去了锁的操作,在一个硬件中断中,运行在硬件中断优先级的cpu将一个dpc排入该cpu对列,中断完毕后cpu降至DISPATCH_LEVEL优先级,dpc得以执行...优先级控制正是windows的一大特色。
综上我们明白了windows异步io的几大要素:1.独立自洽的irp结构;2.优先级的控制。进一步抽象到了windows的设计思想:模块化。windows本身是微内核系统,而微内核就是模块化的。
反观linux的异步io,其实现就是在原来同步阻塞点直接返回,然后在以后重试,负责重试的在老内核不支持异步io的情况下是一系列用户线程,而在 2.6以后是工作队列,而工作队列本质上是一个内核线程,由此可见,linux中并没有和windows对应的dpc的概念,如果非要拉出来一个长得像的,那就是softirq了,但是也就仅仅执行点像,实际上softirq在大多数情况下是由softirqd内核线程执行的,为的就是不让 softirq(dpc?)长期占据处理器,试想一个多网卡的高负载的服务器,softirq几乎占据了很大一块cpu资源,于是乎,不管什么,不管你多 特殊,一律统一接收线程调度程序的调度,这就是公平。而在windows中却显得不那么公平,当然也可以在windows驱动里面自觉地建立内核线程,但是那毕竟不是系统提供的功能啊!
linux和unix一脉相承,简单,公平,统一可能就是它们的品质,一切都是文件,一切接受调度,接口统一;windows相比就显得有些花花绿绿了, 但我还是很欣赏它的优先级控制方案。传统unix本质上是同步的,因为它简单,受控性很好,可预测,所以它稳定,如果在内核一个函数阻塞了,进程不能继续了,unix的做法就是直接调度schedule,而windows的做法就是异步唤醒,然后调整优先级之类的,因为它本质就是异步的。linux最近吸取了unix和windows的优点,所以直接调度和异步唤醒在内核均可见到,不错不错,但是有些乱,变化太快,我很担心如果linux没有一个根本是设 计理念,随着它复杂性增加,代码膨胀,它会不会失控?!
内核稳定性和它们的设计理念有关吗?仅说一点,windows是基于优先级的,dpc在DISPATCH_LEVEL 运行,除了硬中断用户进程无法将它抢占,那么如果它在内核睡眠的话.....而linux一视同仁,内核线程和用户线程统一被调度,当然就不会频繁挂机了....这仅仅从线程化软中断角度讲,实际上linux下的softirq也是不能睡眠的,因为你不能保证每个softirq都在内核线程上下文执行,不过这并不是问题,现在的新内核都将中断给线程化了,还有什么做不到呢?windows的中断请求优先级实际上是一种抽象,将实际执行硬件或软件和执行本身分离,这是非常不错的,简简单单的一个优先级提升或降低加上一个基本原则就可以代替linux的一大堆加锁解锁禁用抢占之操作。
不管是linux还是windows,其本身都运用了统一,简单的思想,只不过用的地方不同,linux提供的vfs,尽量线程化,windows的优先级控制,对象化.....
windows和linux不愧是两大巨猛系统