0.这是我在论坛问的问题
DispacherSend(....)
{
.....
WRITE_PORT_UCHAR(TRANSMIT,0x1);//这里就启动发送,在dispacher没返回pending时,isr就以及发生,dpc已经完成irp,怎么办???同步isr?
return STATUS_PENDING;
}
BOOLEAN OnInterrupt(..)
{
if(TRANSMITINT)
{
IoRequestDpc(...)
}
}
DpcForIsr()
{
IoCompleteRequeset(..)
}
////////////////////////////////////////////////////////////////////////////
1.关于dispacher的irql
wdm书上irql说是dispach_level,但其他章节的叙述看来是passive_level...
2.关于dispacher的返回
返回值到底给了谁?
a)iomgr创建irp
b)iocalldriver本身是同步调用
c)如果iomgr直接iocalldriver,那么返回值给了iomgr,iomgr将做后期处理
d)DPC里iocompleterequest ,将排队dpc obj,最终可能是在apc_level做真正的返回处理
分析:假设dispacher在dispach_level调用
a)在dispacher里return pending前,可能被isr打断,
b)isr里iorequestdpc时,一个dpc入队
c)irql回到dispach_level,假设dpc rountie先于dispacher调用
d)dpc rountie 里面complete irp但所谓完成也是iocomplete obj入队。之后,dispacher应该被resume,即return pending
e)irql到apc_level,排在队列里的iocomplete被完成
f)irql回到passive_level,线程调度恢复,此时win32里的同步deviceiocontrol操作才会真正resume,而得到的值应该是iocomplete obj完成时的,具体应该在一个XXXblock的数据结构里。
这样的分析有两个条件,1)dispacher在dispach_level调用,2)从isr到dispach_level,dpcer可能先于dispacher调用。
如果条件2改为dispacher先调用,也一样,iomgr知道如何处理,我想dispacher里iomarkpending就是起这个作用的,isr来临前dispacher 其实已经放弃了irp,返回值pending到底有什么用不知。或许最终apc complete iocomplete obj时,做判断?
如果条件1改为dispacher在passive_level调用,那么win32 resume和dispacher resume应该也有抢占问题,但这个不重要,只要iomgr把markpending的irp的dispacher的返回值忽略就行。。。。。
没有符号——大陆行货(阉割版)
////////--------------------------------------------------------------------------2009.4.11
翻了翻wrk代码。实际上dispacher是回调函数,对readfile,writefile等win32 api ioctl,其真正调用者应该是iomgr-iocalldriver. 在iomgr的某段代码里面调用了iocalldriver,dispacher的返回值只关系iomgr如何处理。简单的说,iocalldriver返回pending可能会导致iomgr 阻塞。进而阻塞win32线程,实际上中间有一个细节,我想应该说是阻塞一个文件对象(驱动?)所在的上下文,最终才阻塞win32. 当然iomarkirppending可能会让iomgr选择不阻塞。
这样的话,事情就清楚了,对于一个设备——文件句柄。只能有一个IRP pending.,即使在不同的线程中,IRP的一个中间受体是文件,一旦pending就必须完成。即使是non-block IRP,我想也不行!这样的话,必须有一个完成机制,打开另个文件句柄,发个IRP停止是一种做法,walter 的例子也是这么做的,我不知道是不是标准做法,我想应该不是!
我翻阅了src/kernel/serial。它的做法是分时。我想双工driver可以仿照文件行为
1.read行为应该类似普通文件
a) 如果下面有数据,立即返回,如果没有,启动一个timer,以便read返回,这和non-block block IOCTL关系不大。
b) 下面是否有数据,完全决定于驱动设计。对于一个中断设备,可以选择在pending期间才处理接收中断。也可以选择缓冲数据。
c) serial也是用的这种分时方式。
2.write
a)普通文件write也是会超时的。所以write也要提供一个timer
3.显然一个文件不应该同时写和读,即使技术上能实现。
至于排队IRP,书上说,排队是提高吞吐量。我认为排队揭示了一个重要原则,必须提供取消例程。应该说实际上对于一个设备驱动,只能串行处理irp,所谓排队应该有一个隐含条件,另一个设备句柄被打开了,有一个新的irp要处理,但当前的还没处理完,显然直接返回失败不是最好的办法,至少我认为这时排队irp是更好的方法,第二个实体不需要知道错误,它只需要同步挂起,或者overlap.它会在需要时被唤醒。
到目前为止,双工driver可以利用分时方法。双句柄当然可以不用分时,但双句柄有取消IRP.的问题。
总结一下:只为一个实体提供输入输出服务的设备。1.排队不是必须的(只能一个pending,)。2.分时是比较理想的方式3.overlaped是不需要的,因为对于同一个设备句柄,即使两个线程也不能overlap.第二个调用的会返回失败 重叠io正在请求中。我认为没必要花精力处理这种错误