异步输出输入信号处理方法

文档序号:6561164阅读:326来源:国知局

专利名称::异步输出输入信号处理方法
技术领域
:本发明涉及一种信号传送方法,特别涉及一种应用程序使用驱动程序访问外部设备时的输入输出方法。
背景技术
:应用程序一般通过使用驱动程序实现对外部设备的访问,而目前驱动程序可以提供两种操作方式同步输入输出方式(以下简称同步I/0)和异步输入输出方式(以下简称异步I/0)。在同步I/O中,线程启动一个1/0操作然后就立即进入等待状态,直到I/0操作完成后才继续执行。而在异步I/0方式中,线程发送一个I/0请求到内核,然后继续处理其他的事情,内核完成i/o请求后,将会通知线程I/O操作完成了。这个过程如图1所示。同步I/0中,等待l/0操作完成的线程有两种选择第一,不停的查询I/0操作是否完成,这将会使CPU时间全部浪费在等待上,当前线程的工作没有向前推进;第二,可以将自己的CPU时间转让给其他线程使用,以提高整个系统对CPU的使用效率。但是后者带来了线程切换,休眠与唤醒的额外执行开销。如果I/0操作的时间很短,那么这种方法可能得不偿失。另一方面,如果I/0请求需要大量时间执行的话,异步I/0方式可以显著提高效率,因为同步I/0中在线程等待的这段时间内,CPU虽然会调度其他线程进行执行,但是如果系统中没有其他线程需要执行,这段时间将会浪费掉(可能会调度操作系统的IDLE线程)。而异步I/O可以将等待1/0操作的时间留给当前线程使用,使编程者能够自行安排工作利用这段CPU时向,并在必需要确定I/O操作完成情况时才进行相关操作。如果I/O请求操作很快,用异步I/0方式反而还低效,还不如使用同步I/0方式。异步1/0方式如图2所示。同步I/O在同一时刻只允许一个I/O操作,也就是说对于同一个设备驱动的使用是序列化的,即使使用两个线程也不能同时对同一个设备发出读写操作。异步I/0允许多个线程同时发出1/0请求。异步I/O在请求完成时,通过将事件对象设为已通知状态来通知应用程序。应用程序将通过判断对应的事件对象来进行确认。本质上异步I/O就是在设备准备好进行I/O时,用一个信号通知相关的线程。在Windows系统中,异步I/O操作是作为文件系统的功能实现的,可以使用Windows中的多种同步机制,这是一种高阶信号处理行为,但是在开发驱动时并没有提出合适的异步信号处理模型。另一方面,在传统的UNIX系统中,虽然提供基于驱动程序一级的异步1/0,并为其提供一个特殊的信号,然而却对此作出诸多限制,例如,只有流设备才能使用异步1/0,每个进程只有一个这种信号。所以,为了弥补UNIX的不足,又能提供全面的异步1/0支持,需要为驱动程序开发一套全面的异步1/0信号的处理模型。
发明内容本发明要解决的技术问题是提供一种驱动程序级别的异步输入输出信号处理方法,能提供全面的异步1/0支持。为解决上述技术问题,本发明异步输入输出信号处理方法,提供套基于事件的信号处理机制,并在驱动程序的接口上做特殊设计以配合这套信号处理,包括以下步骤-步骤一,作为驱动程序的使用者的用户线程通过驱动程序接口提出进行输入输出信号处理的需要;步骤二,驱动程序创建事件实例,并将其导出给用户线程;步骤三,用户线程通过事件实例获取输入输出处理信号,并根据驱动对信号的定义来完成相应操作;驱动程序完成设备的输入输出操作,通过事件实例来通告用户线程处理信号。本发明在系统仅提供一套简单的同步机制——事件,就从两个方面解决了异步输入输出的难题首先,不需要将异步输入输出操作像Windows编程一样提高到文件系统的高度,并使用各种复杂的同步机制和丰富的系统API;其次,也克服了UNIX系统对驱动层的异步输入输出的各种限制;另一方面,还将事件所导出的信号的语义定义留给驱动设计者,使驱动程序可以提供更加丰富的功能。图1是公知技术中同步输入输出方式的进程示意图;图2是公知技术中异步步输入输出方式的进程示意图;图3是本发明应用于向设备写数据时的流程示意图4是本发明应用于中断服务程序时的流程示意图。具体实施例方式下面结合附图对本发明作进一步详细的说明。首先,从内核对异步输入输出(异步I/O)的事件支持上看,内核提供创建事件和通过事件来通告线程的功能。对于一个事件,线程可以对其进行等待或者尝试等待。然后,在驱动接口层的所有接口都支持一个事件的输出参数(见驱动的接口定义)。当应用程序线程需要进行异步I/O时,它通过驱动程序的接口方法从内核中获取一个事件,并可以在任何时候通过该事件来等待或者尝试等待事件对应设备完成相应的工作。当事件发生时,等待线程还能从事件上获取信号信息。这个信号可以由驱动程序定义其语义,应用线程根据语义做相关处理。这样,有可能仅提供一套简单的事件同步机制和接口上的特殊设计解决异步I/0的问题,同时克服Windows和UNIX的不足;另外,还可以给驱动程序设计者提供丰富的语义能力。基于以上分析,本发明的设计方案可用以下表1、表2、表3来解释,其描述均基于〔++语言。其一,在系统内核中实现事件创建功能,事件通告功能,如下表l:<table>tableseeoriginaldocumentpage7</column></row><table>画T64u640ffset,UINTuNumberOfBytesToRead,EzByteBufebbData,IEvent林ppCompletionEvent);参数说明-u640ffset,要读的数据在设备的偏移值,此参数对于存储类设备(如硬盘)来说,跟扇区相关;uNumberOfBytesToRead,要读的数据的大小;ebbData,读出数据的缓冲区;ppCompletionEvent指向一个IEvent接口指针变量,用来存放所获取的操作同步事件对象的接口指针。参见IEvent接口。当本方法被实现为异步调用时,此操作同步事件对象可以被用来进行调用间同步。返回值说明返回值描述SJ)K方法调用成功E一FAIL未知错误备注此方法将设备内偏移值为u640ffset,大小为uNumberOfBytesToRead字节的数据读入ebbData中。调用成功,返回S—0K,调用失败,返回E一FAIL。Write(<table>tableseeoriginaldocumentpage11</column></row><table>参数说明u640ffset写入设备的偏移值,此参数对于存储类设备(如硬盘)来说,跟扇区相关;ebbData要写入设备的数据缓冲区;puNumberOfBytesWritten实际写入设备的数据的大小的指针;ppCompletionEvent指向一个IEvent接口指针变量,用来存放所获取的操作同步事件对象的接口指针。参见IEvent接口。当本方法被实现为异步调用时,此操作同步事件对象可以被用来进行调用间同步。返回值说明返回值描述S—OK方法调用成功E—FAIL未知错误备注此方法将ebbData中的数据写进设备偏移值为u640ffset的地方。调用成功,返回S—OK,调用失败,返回E—FAIL。INTnControlCode,EzByteBufebblnData,EzByteBufebbOutData,IEvent氺氺ppCompletionEvent),参数说明nControlCode向设备发送的控制命令码;ebblnData向设备发送的命令数据;ebbOutData从设备返回的结果状态等数据;ppCompletionEvent指向一个IEvent接口指针变量,用来存放所获取的操作同步事件对象的接口指针。参见IEvent接口。当本方法被实现为异步调用时,此操作同步事件对象可以被用来进行调用间同步。返回值说明返回值描述S_0K方法调用成功E—FAIL未知错误备注此方法向设备发送命令nControlCode,返回结果状态等数据在ebbOutData内。调用成功,返回SJ3K,调用失败,返回E—FAIL。异步I/O的信号处理流程包含以下步骤步骤一,用户线程(驱动程序的使用者)通过驱动程序接口提出进行异步I/0处理的需要;步骤二,驱动程序创建事件实例,并将其导出给用户线程;步骤三,用户线程通过事件实例获取i/o处理信号,并根据驱动对信号的定义来完成相应操作;驱动程序完成设备的1/0操作,通过事件实例来通告用户线程处理信号。在步骤三中,第一部分,§卩,用户线程通过事件实例获取1/0处理信号并根据驱动对信号的定义来完成相应操作,和第二部分,即,驱动程序完成设备的1/0操作,通过事件实例来通告用户线程处理信号,这两部分的发生顺序没有固定。这种异步1/0处理方法的优点是将一些高级同步机制简化,提供给驱动程序设计者使用;一个用户线程可以同时与多个设备进行异步1/0的操作;驱动程序可自定义异步I/O的信号语义,提供更丰富的功能。在某些系统中,设备驱动程序本质上就是一类存在于内核之中的特殊CAR(ComponentAssemblyRuntime,零部件动态装配)构件,必须通过暴露出一个统的CAR接口IDriver来提供服务。所有的内核驱动程序都提供了一致的IDriver接口,但是一各自特定于设备的方式来解释IDriver接口的精确语义。IDriver接口定义三个标准方法Read,Write和Control,见表3。通常,IDriver接口的Read()方法用于从设备中读入数据;Write()方法用于向设备写数据;而Control()方法则用于向设备发送命令、获取状态信息等等。在这些方法中,本发明定义了一个输出参数IEvent**ppCompletionEvent。如果用户设置该参数为非空,则表示其请求一个异步I/0操作。如果此设备驱动实现了异步1/0,就可以通过此参数返回一个事件对象给用户。当设备完成此异步i/o操作时,通过设置此事件对象为已通知状态来通知用户此次1/0操作的结果。而用户可以在正常启动异步操作之后某个时刻,通过事件对象的Wait或者TryWait方法进行同步。在异步I/0操作过程中,用户调用驱动程序,后者向外部设备发出一次I/0命令后,返回一个事件对象到用户程序。此时用户可以继续进行其它处理,外部设备与CPU并行工作。当设备完成指定的操作时,它会通过中断方式来通知内核作进一步处理。内核会使用对应驱动的中断服务程序(ISR)来完成这个操作若是用户指定的操作尚未完成,驱动ISR对外部设备进行设置之后让设备继续工作;若用户指定操作己经全部完成,则通过设置对应的事件对象为已通知状态来通知用户,并将表示执行结果的状态标志信息传给用户。用户在某个时刻可以使用从驱动中得到的事件对象进行同步若此时事件对象为已通知状态,则其可以继续执行,并从获得的执行结果的状态标志信息中作进一步的判断与处理;若此时事件对象为未通知状态,当前用户线程将进入等待状态,直到事件对象变成己通知状态后被唤醒。当其被唤醒后就意味着IZO操作已完成,并且可以通过传出的状态参数来判断1/0操作的执行情况。本发明应用于ISR时的流程如图4所示。在以上过程中,可以看到在异步1/0的过程中,当驱动ISR工作时,对用户线程的情况是不明确的,即不能确定该用户线程此时的状态,甚至不能假定其仍然存在。所以,如果在ISR中使用到用户线程提供的空间,就可能出现意外。因为一方面(数据空间的存在性),ISR不能确定这段用户空间依然可用,用户线程可能遭遇异常而夭折或者恶意释放这个空间;另一方面(数据的一致性),由于ISR与用户线程都可以使用到这个空间,而这二者是异步执行的,那么这个共用的空间就相当于个竞争资源,可能产生数据不一致。要避免这个问题,可以在驱动中锁定这个特定用户线程的一段空间。但是这种技术比较复杂,驱动会影响用户线程执行,不适合在驱动程序中采用,仅考虑简单的情况——ISR过程不使用用户空间,即Read,Write,Control方法除了ppCompletionEvent参数之外不使用输出类型的参数。那么对于RWC的参数使用上,做一些改变Read方法就不能采用异步I/O的策略(除非用两次读,即ISR将从设备读出的数据暂时存在驱动缓冲区中,用户线程被唤醒后,判断I/O操作是否成功,若成功则再次调用驱动的Read方法将驱动缓冲区的数据读到用户空间)。而对于Write方法,则可以按图3所示的流程,将用户数据拷贝到驱动缓冲区,然后异步发送到设备。对Control方法也使用同样的改变,对于用户到设备的数据,使用驱动缓冲区作为跳板,现将用户数据保存在驱动缓冲区,然后由ISR逐步送到设备;对于设备到用户的数据,除了在I/0完成之后再进行一次驱动缓冲区到用户空间的拷贝之外,尚无其它解决方案。本发明所提供的方法可应用于诸如将用户数据输出到外部设备(典型的就是Write操作),或者使外部设备执行某些不涉及数据传输的操作,例如格式化磁盘,在显存中移动数据等操作中。下面以串口驱动的Write方法为例,在系统中实现异步I/O的操作。首先,来实现用户程序部分#include〈elastos.h〉^include<stdio.h>#defineMAXLEN256int—cdeclmain()Ch虹C;charstrSend[MAXLEN];HRESULThr;IDriver氺pDriver=NULUEzByteBuf—〈MAXLEN〉ebbSend;IEvent氺pEvent=NULUUINTuSend;inti5DWORDdwStat二0;〃获取串口驱动的服务对象hr=EzFindService(EZCSTR(〃device:aseriall"),(10bject氺氺)&pDriver);if(FAILED(hr)){printf(〃Err:Noserialdriver\n〃);return-l;〃读取键盘输入,以$作为结束符,长度不超过區XLEN:for(i=0;i<證LEN;i++){if('$'!二(c=getchar())){strSend[i]二strSend[i+l]二0;elsebreak^〃如果有键盘输入,将其发到串口if(i〉0){〃将待发送数据拷贝到EzByteStr中ebbSend.Copy(strSend,i)5〃调用驱动接口的Write方法hr=pDriver—〉Write(0,ebbSend,&uSend,&pEvent);〃从驱动正常返回之后可以继续执行一些其它操作,例如printf("%d:%s\n",ebbSend.Used(),(char氺)ebbSend);〃与10操作进行同步printf("Waitforevent!\n");hr二pEvent-〉Wait(&dwStat);if(FAILED(hr)){printf("waiteventfailed\n");gotoExit;printf(〃I0operationfinished.SendBytes:%d\n〃,dwStat);Exit:if(pDriver)pDriver-〉Release();if(pEvent)pEvent_>Release();if(FAILED(hr)){gotoExit;〃对10操作结果作相应处理:returnlmif(pDriver)pDriver->Release(),if(pEvent)pEvent->Release0;return0;用户程序首先获得串口驱动对象,然后从键盘读数据,并将这些数据通过串口驱动的Write方法发送到串口输出,接着做一些其它处理后,与1/0操作进行同步,并作相应处理,最后退出。驱动的实现部分仅仅关注串口的Write方法和其Isr。Write方法进行异步操作过程如下HRESULTCASerial::Write(/*[in]*/UINT64u640ffset,/*[in]*/EzByteBufebbData,/*[out]*/UINT*puNumberOfBytesWritten,/氺[out]氺/IEvent氺氺ppCompletionEvent)if(ebbData.IsNull()iI0=ebbData.Used()){returnE—丽ALIDARG;HRESULThr;m一writeLock.Lock();if(!ppCompletionEvent){〃同步IO操作〃……else{〃异步10操作〃检测驱动缓冲区是否还有足够大的空间if((UINT)ebbData.Used()〉(TXASYNQUEUE-m一uUsedTxAsyncQueue)){hr二E—FAIL;gotoExit^〃将数据拷贝到驱动缓冲中if(!ByteCpy(ebbData)){hr二E—FAIL;gotoExit;〃将驱动创建的事件对象输出给用户if(m—pTxAsynEvent){〃正在进行异步操作hr二E—FAIL;gotoExit;else{hr=CreateEventObj(FALSE,0,&m—pTxAsynEvent);if(FAILED(hr)){kprintf("Can,tcreateAsynTXEvent\rT);m—pTxAsynEvent=NULL;gotoExit;if(!puNumberOfBytesWritten)*puNumberOfBytesWritten=0;m—pTxAsynEvent-〉AddRef();氺ppCompletionEvent二m—pTxAsynEvent;〃设置当前输出数据为0:〃设置I0状态信息(用于记录传送字节数目):m—dwError=0;〃打开发送寄存器为空时的中断:UART—ENABLE—TX—INTS(m—iobase);S—OK;Exit:m—writeLock.Unlock();returnhr;Write方法在进行异步操作的过程中主要完成检测驱动缓冲区是否能容纳用户数据;将用户数据拷贝到驱动缓冲区中;创建并导出事件对象;开启传送缓冲为空时的中断。驱动ISR过程如下voidCASerial::Isr()〃获取串口控制器状态UINTulntStat二DART—READ—INT—STAT(m—iobase);〃判断是否为传送寄存器为空,且执行异步I0:if(UART—IS—TX—INT(ulntStat)&&m—pTxAsynEvent){if(m—uUsedTxAsyncQueue){〃驱动缓冲中是否还有数据待发送〃将-个字节数据传到发送寄存器while(UART—READ—LS—ET服(m—iobase))〃m—uUsedTxAsyncQueueUART—WRITE—TX_BUF(m—iobase,FetchByte());m—dwError++-,}else{〃数据传送完毕〃关闭传送中断UART—DISABLE_INTS(m—iobase);UART—DISABLE—INTS(mjobase);UART—DISABLE—INTS(mjobase);〃通知用户线程,返回IO执行状态NotifyEventObjBylsr(m一pTxAsynEvent,m—dwError);m—dwError=0;m—pTxAsynEvent-〉Release0;m—pTxAsynEvent=NULL;else{〃处理其它中断情况驱动ISR所作的工作主要是判断驱动缓冲区是否还有数据待发送,若有就将一个字节传送到串口发送寄存器上;若没有,就关闭中断通知用户程序。运行结果,启动用户程序ComAsynIOTest后,首先输入一组数据,以$作为结束,可以看见提示信息"Waitforevent!",然后过一会儿会继续出现"10operationfinished.SendBytes:XX"。例如ComAsynIOTest012345678901234567890123456789.$Waitforevent!10operationfinished.SendBytes:31与微软的异步I/0相比,本发明所提供的方法要求用户提供一个事件对象后传递给文件对象,而不是仅仅针对驱动。并且通过GetOverlappedResult操作来査看执行结果,相对比较复杂。而本发明的事件对象比微软的多返回一个附加的DWORD参数,可以借此获知异步I/0的完成情况,比微软的异步I/0要更简洁。权利要求1、一种异步输入输出信号处理方法,包括以下步骤步骤一,作为驱动程序的使用者的用户线程通过驱动程序接口提出进行输入输出信号处理的需要;步骤二,驱动程序创建事件实例,并将其导出给用户线程;步骤三,用户线程通过事件实例获取输入输出处理信号,并根据驱动对信号的定义来完成相应操作;驱动程序完成设备的输入输出操作,通过事件实例来通告用户线程处理信号。2、根据权利要求1所述的异步输入输出信号处理方法,其特征是,所述事件包括已通知或未通知两种状态;当事件对象处于未通知状态时,所有等待此事件对象的线程将全部进入等待状态;当事件对象处于已通知状态时,等待此事件对象的线程则不会进入等待状态。3、根据权利要求2所述的异步输入输出信号处理方法,其特征是,所述事件包括手动重置或自动重置两种类型,事件对象的类型是在创建时由传入的类型参数指定的;手动重置的事件可设置为所述已通知状态或所述未通知状态,手动重置的事件对象保持已通知状态,直到被重置为未通知状态为止;自动重置的事件对象可设置为所述己通知状态或所述未通知状态,自动重置的事件对象在一个线程被唤醒后自动重置为未通知状态。4、根据权利要求3所述的异步输入输出信号处理方法,其特征是,所述事件的未通知状态只有一个预定义的状态,已通知状态有一个或者任意多个。5、根据权利要求4所述的异步输入输出信号处理方法,其特征是,所述事件的已通知状态由用户自行定义的一个非零无符号整数表示。全文摘要本发明公开了一种异步输入输出信号处理方法,提供一套基于事件的信号处理机制,并在驱动程序的接口上做特殊设计以配合这套信号处理,包括以下步骤步骤一,作为驱动程序的使用者的用户线程通过驱动程序接口提出进行输入输出信号处理的需要;步骤二,驱动程序创建事件实例,并将其导出给用户线程;步骤三,用户线程通过事件实例获取输入输出处理信号,并根据驱动对信号的定义来完成相应操作;驱动程序完成设备的输入输出操作,通过事件实例来通告用户线程处理信号。将一些高级同步机制简化,提供给驱动程序设计者使用;一个用户线程可以同时与多个设备进行异步I/O的操作;驱动程序可自定义异步I/O的信号语义,提供更丰富的功能。文档编号G06F9/46GK101158912SQ200610116898公开日2008年4月9日申请日期2006年10月8日优先权日2006年10月8日发明者毅张,王晨辉,苏翼鹏申请人:上海科泰世纪科技有限公司
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1