具体实施方式
下面将结合本发明实施例中的附图,对本发明实施例中的技术方案进行清楚、完整地描述,显然,所描述的实施例是本发明一部分实施例,而不是全部的实施例。基于本发明中的实施例,本领域普通技术人员在没有做出创造性劳动前提下所获得的所有其他实施例,都属于本发明保护的范围。
实施例一
图2A为根据本申请实施例的任务处理***架构图。
如图2A所示,任务处理***包括一个或多个CPU和硬件资源(例如,队列), CPU耦合到多个队列(入站队列0、入站队列1、出站队列0、出站队列1),用于同外部设备交换消息。CPU运行存储器中的任务调度层程序与处理任务的程序,例如处理任务的代码段。
CPU上可同时处理多个任务,在图2A所示的例子中,CPU上包括处理任务 0的代码段(用“任务0”指示)、处理任务1的代码段(用“任务1”指示)、处理任务2的代码段(用“任务2”指示)、处理任务3的代码段(用“任务3”指示)和处理任务4的代码段(用“任务4”指示)。多个任务按一定顺序处理,协同实现任务处理***的功能(例如,处理访问存储设备的IO命令)。在每个任务中可以指定其后续任务,或者响应于不同事件的不同后续任务。例如,任务0的后继任务之一是任务2,任务1的后继任务之一是任务0,而任务4的后继任务是任务3。作为举例,每个任务均实现IO命令处理的一个阶段。而在任务处理***中,可同时处理多个IO命令。相应地,为每个IO命令提供上下文资源(Context),处理任务的代码段可使用上下文资源来区分对不同IO命令的处理。
当被CPU运行时,任务调度层程序为处理任务的代码段提供API(应用程序编程接口,Application Programming Interface)。处理任务的代码段通过调用API 告知任务调度层程序其所要操作的硬件(例如,队列),由任务调度层程序检查硬件状态,并在硬件资源可用时,操作硬件完成处理任务的代码段通过API所请求的操作。可选地,处理任务的代码段通过调用API还注册用于处理事件的其他代码段,例如,向出站队列1填充消息,又从入站队列1接收到响应消息后,由处理任务2的代码段来处理。任务调度层程序响应于入站队列1上出现消息,调用处理任务2的代码段。
在根据本申请的实施例中,任务调度层程序通过API为处理任务的代码段提供运行环境,其具有以下优点:
(1)任务调度层程序提供的API是异步的,处理任务的代码段调用API后,所调用的API立刻返回,不会阻塞处理任务的代码段的执行;
(2)任务调度层程序处理硬件操作,向处理任务的代码段屏蔽硬件操作细节与差异性,使得处理任务的代码段无须关注硬件资源可用性和/或硬件处理的延迟;
(3)任务调度层程序根据硬件资源的状态调度适当的代码段,安排各个代码段的执行顺序,以平衡任务处理的延迟与CPU执行效率。
图2B为根据本申请实施例的对处理任务的代码段调度执行的示意图。图2B 中,从左向右的方向是时间流逝的方向。实线箭头指示了任务处理的时间顺序,虚线箭头指示了任务处理的逻辑顺序。
对于单一CPU,任一时刻仅能处理一段代码。示例性地,如图2B所示,对于待处理的多个代码段,先执行处理任务0的代码段、接下来执行处理任务1的代码段、接下来执行处理任务4的代码段、接下来执行处理任务2的代码段、接下来执行处理任务0的代码段以及接下来执行处理任务3的代码段。而在各个处理任务的代码段中指示了任务处理的逻辑顺序,例如,该逻辑顺序包括任务2要在任务0之后处理、任务0在任务1之后处理、任务3在任务4之后处理等。
通过使用任务调度层程序,向任务调度层程序提供的应用程序编程接口注册进行后续处理的代码段,使得在处理任务的代码段中仅需依照任务的逻辑顺序指定其后继代码段,由任务调度层程序在满足逻辑顺序的要求下,在CPU上调度处理任务的代码段。
在根据本申请的实施例中,处理任务的代码段无须检查硬件资源可用性,无须维护多个处理任务的代码段之间的顺序,提升了CPU利用率,也降低了处理任务的代码段的复杂度。
图3是根据本申请实施例的任务调度层程序进行任务调度地示意图。
CPU可用的硬件资源包括多个队列,例如,入站队列与出站队列(参看图1)。硬件资源还包括存储器、定时器等。为协助处理任务的代码段发送消息,任务调度层程序提供注册(register)API、发送(SendMessage)API等API。
在一个例子中,如图3所示,当被CPU运行时,任务调度层程序维护硬件资源状态表,使用硬件资源状态表记录各个硬件资源的状态。例如,在硬件资源状态表中,记录每个队列是否可用。对于入站队列,队列可用意味着入站队列中出现待处理的消息。对于出站队列,队列可用意味着可向出站队列添加消息以发送给队列的接收方。对于定时器,定时器可用意味着定时器到时或定时器未在计时。对于存储器,存储器可用意味着存储器控制器空闲,向存储器完成了数据写入操作或从存储器读出了数据。
如图3所示,当被CPU运行时,任务调度层程序还维护处理函数表,处理函数表记录已注册的同各个硬件资源对应的处理函数。响应于硬件资源可用,调用从处理函数表获取同可用的硬件资源对应的处理函数。
可选地,将硬件资源状态表与处理函数表集成在单一表中。以硬件资源作为表条目的索引,在表条目中记录硬件资源的状态以及处理函数。依然可选地,在该单一表中仅记录可用的硬件资源,响应于硬件资源可用,在单一表中添加对应于可用硬件资源的条目,以及响应于硬件资源不可用,从单一表中删除对应于不可用资源的条目,从而可省略对硬件资源的状态的记录。
在再一个例子中,如图3所示,当被CPU运行时,任务调度层程序还维护上下文表,上下文表用于记录被缓存的上下文(mContext)。
可选地,在处理函数表中,记录同要处理的各个消息对应的处理函数,以及在上下文表中记录同各个消息对应的被缓存的上下文(mContext)。
如图3所示,在CPU初始化阶段,作为举例,处理任务的代码段通过注册(Register)API向任务调度层程序为一个或多个队列注册发送消息的处理函数 (例如,被注册给出站队列的处理函数messageOutboundCallback或被注册给入站队列的处理函数messageInboundCallback)(301)。任务调度层程序,作为响应,将队列及其关联的处理函数记录在处理函数表中。
作为又一个例子,处理任务的代码段通过注册API(例如,Register(qID,messageInboundCallback))指定入站队列(qID)与操作硬件(由qID所指示的入站队列)以接收消息的处理函数(messageInboundCallback)(301)。任务调度层程序,作为响应,将由qID指示的队列及其关联的处理函数(messageInboundCallback)记录在处理函数表中。
在步骤302,处理任务的代码段通过发送(SendMessage)API指示要通过由 qID所指示的队列发送消息(mContext)。任务调度层程序,作为响应,将由qID 指示的队列及其关联的上下文记录在上下文表中。
注册与发送API都是异步的,被调度后不会阻塞处理任务的代码段。注册与发送API可被多次调用,以注册多个处理函数,或发送多个消息。
响应于入站队列中存在待处理消息,任务调度层程序调用操作硬件以接收消息的处理函数(messageInboundCallback)(303)。
响应于出站队列中存在待处理消息,任务调度层程序调用执行操作硬件以发送消息的处理函数(messageOutboundCallback)(304)。
在图3中,作为举例,步骤301与步骤304相关。通过步骤301,将处理函数(messageInboundCallback)与由qID指示的入站队列注册给任务调度层程序;而在由qID指示的入站队列有待处理消息时(步骤304),任务调度层程序调用同由qID指示的入站队列相关联地注册的处理函数(messageInboundCallback)。
步骤302中,没有指定同由qID指示的出站队列相关联地注册的处理函数。需要通过其他对注册API的调用,以使任务调度层程序在处理函数表中记录同由 qID指示的出站队列相关联地注册的处理函数。并由任务调度层在由qID指示的出站队列可用时,通过处理函数表获得相关联的处理函数,以及通过上下文表获得要在由qID指示的出站队列上发送的消息。并调度处理函数来发送消息。
任务调度层程序循环处理步骤310、步骤320与步骤330。
在步骤310,任务调度层程序,获取可用的硬件资源。示例性地,通过访问硬件资源状态表,获取可用的硬件资源(例如,队列)。在一个例子中,当队列可用时,硬件设置对应的状态寄存器指示队列可用,将状态寄存器作为硬件资源状态表的表项。在另一个例子中,当队列可用时产生中断,在中断处理例程中依据可用的队列设置硬件资源状态表的表项。
可选地,若硬件资源状态表指示没有可用的硬件资源,忽略对步骤320与步骤330的执行,从而降低对CPU的利用率。依然可选地,响应于硬件资源状态表指示没有可用的硬件资源,任务调度层程序使自身暂时休眠,或者使CPU休眠,以降低功耗。以及响应于有可用的硬件资源,还恢复对任务调度层程序的执行和/或唤醒CPU。
接下来,在步骤320中,任务调度层程序获取同可用的硬件资源相关联的处理函数。并在步骤330中,调用处理函数。作为一个例子,响应于在步骤310获知入站队列0可用,在步骤320访问处理函数表,以获取同入站队列0相关联的处理函数,并调用该处理函数。可选地,还将可用队列的信息作为参数提供给处理函数。
依然可选地,同队列相关联的处理函数还需要上下文。示例性地,可通过访问上下文表获取同队列相关联的上下文(例如,要通过队列发出的消息),并将获取的上下文也作为参数提供给同队列相关联的处理函数。
在处理函数执行完成,调用处理函数的步骤330执行完成,返回步骤310,并再次获取可用的硬件资源并基于可用的硬件资源进行处理。
作为又一个例子,响应于出站队列0可用,在步骤320获取同出站队列0关联的处理函数。可选地,若处理函数表中不存在同出站队列0关联的处理函数,则步骤320处理完成,并略过对步骤330的处理,而返回步骤310再次获取可用的硬件资源。依然可选地,同同出站队列0关联的处理函数需要上下文,而访问上下文表未得到对应的上下文,则步骤320处理完成,并略过对步骤330的处理,而返回步骤310再次获取可用的硬件资源。
在一个例子中,处理函数使用可用的硬件资源,并使得可用的硬件资源变为不可用。在又一个例子中,处理函数不使用硬件资源,进而在处理函数执行完成后,导致该处理函数被调用的可用的硬件资源依然可用。在另一个例子中,任务调度层程序使用可用的硬件资源并提供给处理函数,使得无论处理函数是否使用硬件资源,可用的硬件资源都将变为不可用。在依然又一个例子中,可用的硬件资源有多份,任务调度层程序或处理函数使用可用的硬件资源的一份。
处理函数属于处理任务的代码段。在处理函数中可通过注册API向任务调度层程序更改注册到一个或多个队列的处理函数,或者通过发送API向任务调度层程序指示有消息要通过指定的出站队列(由qID指示的出站队列)发出。在发送 API中还指示要发送消息的上下文,可选地,在发送API中还指示处理函数。作为响应,任务调度层程序将出站队列及其关联的要发送消息的上下文记录在上下文表中,将出站队列及其关联的处理函数记录在处理函数表中。
可选地,硬件资源也可以是除队列外的其他类型的消息传递装置。例如,消息传递装置可包括用于外发消息的出站消息传递装置以及用于接收消息的入站消息传递装置。消息传递装置可包括多个槽,各个槽可彼此独立的传递消息,以及各个槽之间传递的消息没有顺序约束。对槽的分配由任务调度层处理。处理任务的代码段可仅指示发送消息的消息传递装置。
在一个例子中,任务调度层程序在指定的消息传递装置上有可用的槽时,调用处理函数来发送上下文中指示的消息。在另一个例子中,发送API中指示要发送消息的上下文、消息的接收方(而非消息传递装置)以及处理函数,而由任务调度层程序分配消息传递装置,并将分配的消息传递装置与处理函数记录在处理函数表中。
根据图3的实施例,任务调度层程序与处理任务的代码段都无须等待硬件对消息传递的完成,有助于提高CPU利用率。
实施例二
图4是根据本申请实施例的发送消息的流程图。作为举例,图4所示的发送消息的方法用来将消息发送给其他CPU。
为协助处理任务的代码段发送消息,任务调度层程序提供注册(register)API、发送(SendMessage)API等API。通过注册API向任务调度层程序注册事件的处理函数(例如,操作硬件以发送消息的处理函数),当出现指定的事件(例如硬件资源可用),任务调度层程序调用所注册的处理函数以执行发送消息的过程。从而即使运行在不同的硬件平台上,通过修改事件的处理函数得以在不改变代码段结构的情况下,适配不同硬件平台的差异。
如图4所示,为发送消息,在步骤410,处理任务的代码段通过注册API(例如,Register(qID,messageOutboundCallback))指定出站队列(qID)与操作硬件以发送消息的处理函数(messageOutboundCallback)。与之对应地,在步骤401,任务调度层程序在处理函数表中记录硬件资源(例如,由qID指示的出站队列) 与处理函数(messageOutboundCallback)的映射关系。在步骤420,处理任务的代码段通过发送API(SendMessage(qID,mContext))指示出站队列(qID)上有待发送的消息(mContext)时,任务调度层程序调用同出站队列(qID)关联的处理函数(messageOutboundCallback)。任务调度层程序还决定调用处理函数(messageOutboundCallback)的时机。在步骤403,响应于硬件资源可用(例如,出站队列(qID)非满),调用注册的处理函数,使得处理函数(messageOutboundCallback)被执行时(430),出站队列(qID)可被添加消息。
作为举例,在步骤410中,注册API(例如,Register(qID,messageOutboundCallback))并未指定待发送的消息。
在需要发送消息时,在步骤420中,处理任务的代码段通过调用发送API(SendMessage(qID,mContext))向任务调度层程序指示有消息要通过指定的出站队列(由qID指示的出站队列)发出,以及还指示要发送消息的上下文(mContext) (例如,待发送消息本身,或者消息的存储地址与长度)。
任务调度层程序响应于发送API被调用,在上下文表缓存指定的出站队列 (qID)与消息上下文(mContext),并立即返回(402),从而调用发送API的处理任务的代码段无须等待消息通过硬件被真实地发送,即可处理后续的操作。
步骤410与步骤420无须连续的执行。例如,在初始化阶段,处理任务的代码段执行步骤410,而在需要发送消息时,执行步骤420。但步骤410与步骤420 具有关联性(由虚线箭头指示)。在注册API中,指定了例如出站队列(qID)的处理函数,而在发送API中指定了出站队列(qID)上要发送的消息,而任务调度层调度注册API中指定的处理函数来在出站队列(qID)上发送由发送API所指定的消息。
任务调度层程序检查指定的出站队列的状态(也参看图3的步骤310)。在指定的出站队列(qID)的硬件资源可用(例如,出站队列非满),调用在指定的出站队列上注册的处理函数(messageOutboundCallback)(403、430)。而在处理函数messageOutboundCallback中直接使用可用的硬件资源以操作硬件发送消息 (mContext)。
在上面的例子中,发送API(SendMessage(qID,mContext))没有指定处理函数,任务调度层程序基于注册API(Register(qID,messageOutboundCallback))指定的处理函数,在指定队列(qID)可用时调用指定的处理函数 (messageOutboundCallback)。
步骤420与步骤430无须连续的执行,但步骤420中指示了要在接下来执行步骤430。在步骤420执行后,任务调度层程序依据硬件资源的状态确定步骤430 的执行时机。可选地,在调用发送API时指定处理函数 (messageOutboundCallback),从而无须通过注册API在出站队列与处理函数之间建立固定的映射关系。另外,可由发送API也注册处理函数,从而为每次消息发送建立与处理函数的映射关系,增强消息发送过程的灵活性。可以理解地,虽然上面将处理函数用单一的名字描述,但是可在每次注册处理函数时,指定不同的处理函数。
依然可选地,响应于调用发送API,任务调度层程序检查所使用的硬件资源 (例如,由qID所指示)是否可用。若硬件资源可用,可无须缓存上下文而直接调用处理函数。而仅在所使用的硬件资源不可用时,才缓存上下文并立即返回。
图5是根据本申请实施例的接收消息的流程图。
为协助处理任务的代码段接收消息,任务调度层程序提供注册(register)API 等API。通过注册API向任务调度层程序注册操作硬件以接收消息的处理函数,当硬件指示入站队列中出现消息时,任务调度层程序会调用所注册的处理函数以执行接收消息的过程。从而即使运行在不同的硬件平台上,通过修改操作硬件以接收消息的处理函数得以在不改变代码段结构的情况下,适配不同硬件平台的差异。
如图5所示,为接收消息,在步骤510,处理任务的代码段通过注册API(例如,Register(qID,messageInboundCallback))指定入站队列(qID)与操作硬件以接收消息的处理函数(messageInboundCallback)。与之对应地,作为响应,在步骤501,任务调度层程序在处理函数表中记录硬件资源(入站队列(qID))与处理函数(messageInboundCallback)的映射关系。任务调度层程序响应于硬件资源 (入站队列(qID))可用,在步骤502,调用注册的处理函数 (messageInboundCallback)。处理函数(messageInboundCallback)属于处理任务的代码段的部分。在步骤520,处理函数(messageInboundCallback)被执行。
可选地,通过执行处理函数(messageInboundCallback),直接使用可用的硬件资源,通过操作硬件接收消息。
可选地,通过注册API(Register())向任务调度层程序指示处理函数的多种使用方式。在一个实施方式中,响应于入站队列(qID)中出现消息,任务调度层程序调用处理函数(messageInboundCallback),并且任务调度层程序假定处理函数(messageInboundCallback)必然会处理入站队列(qID)中出现的(指定数量(例如1个)的)消息。以及任务调度层程序检查入站队列(qID)中被取出指定数量的消息后是否依然存在消息而决定是否再次调用处理函数 (messageInboundCallback)。在另一个实施方式中,响应于入站队列(qID)中出现消息,任务调度层程序调用处理函数(messageInboundCallback),并且由处理函数(messageInboundCallback)决定是否从入站队列(qID)中取出消息。若处理函数(messageInboundCallback)未从入站队列中取出消息,任务调度层程序将基于入站队列(qID)中依然存在待处理消息而再次调用处理函数(messageInboundCallback);若处理函数(messageInboundCallback)从入站队列 (qID)中取走消息,任务调度层程序检查入站队列(qID)中被取出消息后是否依然存在消息而决定是否再次调用处理函数(messageInboundCallback)。
为协助处理任务的代码段访问外部存储器,任务调度层程序提供用于访问外部存储器的API,包括读存储器(readMemory)API、写存储器(writeMemory) API、同步读存储器(readMemorySync)API、同步写存储器(writeMemorySync)API、存储器复制(copyMemory)API等API。
通过用于访问外部存储器的API向任务调度层程序注册事件的处理函数(例如,对从外部存储器读取的数据进行处理的处理函数(memoryCallback)),当出现指定的事件(例如外部存储器操作完成),任务调度层程序会调用所注册的处理函数以执行后续操作。
图6是根据本申请实施例的从外部存储器读数据的流程图。
如图6所示,在步骤610,处理任务的代码段通过读存储器API(例如, readMemory(src,dest,memoryCallback))指定源地址(src)、目的地址(dest) 与处理函数(memoryCallback),其中处理函数用于响应外部存储器操作完成。
与之对应地,在步骤601,任务调度层程序响应于读存储器API(例如, readMemory(src,dest,memoryCallback))被调用,缓存读存储器操作的上下文(例如,上下文包括源地址、目的地址、数据大小、指定的处理函数等),并返回,使得处理任务的代码段可继续执行其他操作。
在步骤602,任务调度层程序响应于访问外部存储器的硬件资源可用(例如,存储器控制器空闲,访存队列空闲等),获取缓存的上下文,从外部存储器读出数据,将读出的数据写入目的地址。接下来,任务调度层程序调用指定的处理函数(memoryCallback),作为对事件(读存储器完成)的响应。处理函数 (memoryCallback)属于处理任务的代码段的部分。与之对应地,在步骤620,处理函数(memoryCallback)被执行。
可选地,读存储器API还指定读取数据的大小。可选地,源地址位于外部存储器中,而目的地址位于例如CPU的本地存储器。
读存储器API是异步的,该API被调用后会立即返回,而不会阻塞CPU的运行。处理任务的代码通过读存储器API还指定处理函数(memoryCallback),用于在读存储器操作完成后(数据被写入目的地址)执行后续处理。
可选地,从目的地址访问数据的过程分为两个阶段:向外部存储器发出读存储器请求,与从外部存储器接收读取的数据。两个阶段之间可能存在较长的延迟。任务调度层程序在执行了向外部存储器发出读存储器请求阶段后,再次缓存上下文,并在硬件资源可用(外部存储器提供了读取的数据)后,再获取缓存的上下文,将数据写入目的地址,并调用指定的处理函数,以缩短延迟。
可选地,调用读存储器API(例如,readMemory(src,dest)时不指定处理函数。任务调度层程序完成读取存储器操作后也不调用处理函数。
从存储器读取数据是为了使用数据。根据本申请的实施例,任务调度层程序在从存储器读取了数据后,调用处理函数(memoryCallback)对读取的数据进行处理,从而无须处理任务的代码段等待或反复查询是否从存储器读取了数据。消除了异步存储器访问方式所引入的额外开销,降低了处理任务的代码段的编程复杂度。
图7是根据本申请实施例的向外部存储器写数据的流程图。
如图7所示,在步骤710,处理任务的代码段通过写存储器API(例如, writeMemory(src,dest,memoryCallback))指定源地址(src)与目的地址(dest)。目的地址位于外部存储器中,而源地址位于例如CPU的本地存储器。可选地,写存储器API还指定写数据的大小。写存储器API是异步的,该API被调用后会立即返回,而不会阻塞CPU的运行。
任务调度层程序响应于写存储器API(例如,writeMemory(src,dest,memoryCallback))被调用,缓存读存储器操作的上下文(例如,上下文包括源地址、目的地址、数据大小等),并返回(701),使得处理任务的代码可继续执行其他操作。
任务调度层程序响应于访问外部存储器的硬件资源可用(例如,存储器控制器空闲,访存队列空闲等),获取缓存的上下文,向外部存储器写入数据。
可选地,写存储器API还指定处理函数(memoryCallback)。处理函数(memoryCallback),用于在写存储器操作完成后(数据被写入目的地址)执行后续处理。
响应于向存储器写入了数据,在步骤702,任务调度层程序调用指定的处理函数(memoryCallback),作为对事件(写存储器完成)的响应。与之对应地,处理函数(memoryCallback)被执行。作为一个例子,在处理函数(memoryCallback) 中向另一处理器发消息以指示该另一处理器可访问被写入存储器的数据。可选地,在消息中携带函数指针,该另一处理器通过调用函数指针所指示的函数,来访问被写入存储器的数据。
可选地,向外部存储器的目的地址写入数据的过程分为两个阶段:向外部存储器发出写存储器请求,与从外部存储器接收写入完成的指示。两个阶段之间可能存在较长的延迟。任务调度层程序在执行了向外部存储器发出写存储器请求阶段后,再次缓存上下文,并在硬件资源可用(外部存储器指示写存储器完成)后,再获取缓存的上下文,并调用指定的处理函数,以缩短延迟。
可选地,调用写存储器API(例如,writeMemory(src,dest))时不指定处理函数。任务调度层程序完成写取存储器操作后也不调用处理函数。
类似地,处理任务的代码段通过存储器复制(Copy(src,dest))API指定源地址(src)与目的地址(dest),以将源地址的数据复制到目的地址。源地址与目的地址均位于外部存储器中。由任务调度层处理存储器复制操作。
此外,在根据本申请的实施例中,还提供同步读存储器API、同步写存储器 API等API。处理任务的代码段调用同步读存储器API或同步写存储器API后,在任务调度层程序完成了存储器访问操作后,才返回处理任务的代码段继续执行。此时,处理任务的代码段已可以使用从存储器获取的数据。
图8是根据本申请实施例的使用用户事件的流程图。
在根据本申请的实施例中,处理任务的代码段可通过应用程序编程接口向任务调度层程序注册响应用户事件的处理函数以及触发用户事件的触发条件。例如,触发条件包括:触发事件的时间,和/或触发事件的次数。任务调度层程序依据所指定的触发条件调用处理函数。任务调度层程序提供注册(register)API,用于注册事件。如图8所示,在步骤810,处理任务的代码通过注册API(例如, Register(eventID,userEventCallback))为事件指定标识符(eventID)以及响应事件的处理函数(userEventCallback)。响应作为,在步骤801,任务调度层程序记录事件(例如,记录事件的标识符(eventID))与其处理函数(userEventCallback)的映射关系。
在一个实施方式中,任务调度层程序还提供触发API(例如,TriggerUserEvent(eventID))。在步骤820,处理任务的代码段通过调用任务调度层程序提供的触发API来产生指定事件(由事件标识符(eventID)所指示)。与之对应地,在步骤802,任务调度层程序缓存指定事件的上下文(标识符(EventID)等),例如,记录由eventID所指示的事件已产生的状态,并返回,使得处理任务的代码得以继续执行。
任务调度任务调度层程序通过缓存的上下文,获取处于已产生状态的事件,进而获取同已产生事件对应的已注册的处理函数(userEventCallback)。在步骤 803,,任务调度层程序调用注册的处理函数(userEventCallback),与之对应地,在步骤830,同用户事件相关联的处理函数(userEventCallback)被执行。
可选地,触发API中还可指定触发事件的条件。在另一个实施方式中,在注册API中明示或暗示触发事件的条件,而无须使用触发API。由任务调度层程序从缓存的上下文中识别触发事件的条件,在条件满足时,调用已注册的处理函数。
图9是根据本申请实施例的从外部非易失存储器(NVM,Non-Volatile Memory)读数据的流程图。
为协助处理任务的代码段访问外部NVM,任务调度层程序提供用于访问 NVM的API,包括读NVM(readNVM)、写NVM(writeNVM)、设置NVM (SetNVM)API等。
在步骤910,处理任务的代码段通过读NVM API(例如,readNVM(dest, pba,NVMCallback))指定源地址(pba)与目的地址(dest),以将NVM上的由源地址所指示的数据读出并存储到由目的地址(dest)所指示的位置。可选地,读NVM API还指定读取数据的大小。目的地址位于外部存储器或CPU的本地存储器中。读NVM API(readNVM(dest,pba,NVMCallback))是异步的,该读 NVM API(readNVM(dest,pba,NVMCallback))被调用后会立即返回,而不会阻塞CPU的运行。处理任务的代码通过读NVM API(readNVM(dest,pba,NVMCallback))还指定处理函数(NVMCallback),用于在读NVM操作完成后 (即数据被从NVM读出)执行后续处理。
在步骤901,任务调度层程序响应于读NVM API(readNVM(dest,pba,NVMCallback))被调用,缓存读NVM操作的上下文(例如,上下文包括源地址、目的地址、数据大小、指定的处理函数等),并返回,使得处理任务的代码段可继续执行其他操作。
任务调度层程序响应于访问NVM的硬件资源可用(例如,介质接口控制器空闲等,在中国专利申请CN201610009789.6、CN201510253428.1、 CN201610861793.5、CN201611213755.5、CN201611213754.0中提供了多种介质接口控制器,也可使用现有技术中的访问闪存等NVM的介质接口控制器),获取缓存的上下文,将从源地址读取数据的请求发送给介质接口控制器。从介质接口控制器接收要读取数据的请求到NVM输出数据有较大的延迟。任务调度层程序在执行了向介质接口控制器发送从NVM读取数据的请求,再次缓存上下文,并在硬件资源可用(介质接口控制器提供了从NVM读取的数据)后(902),再获取缓存的上下文,并调用指定的处理函数(920),以缩短延迟。
可选地,处理函数用于将读出的数据通过DMA操作发送给主机,或者在读出数据存在错误时执行数据恢复或错误处理。
可选地,读NVM API可指定一段或多段连续或不连续的源地址和/或目的地址,以从NVM的多个位置获取数据。
图10是根据本申请实施例的向外部非易失存储器(NVM,Non-Volatile Memory)写数据的流程图。
在步骤1010,处理任务的代码段通过写NVM API(例如,WriteNVM(sec, pba,NVMCallback))指定源地址(src)与目的地址(pba),以将源地址处的数据写入NVM上由目的地址所指示的位置。可选地,写NVM API还指定读取数据的大小。源地址位于外部存储器或CPU的本地存储器中。写NVM API是异步的,该写NVM API被调用后会立即返回,而不会阻塞CPU的运行。处理任务的代码通过写NVM API还指定处理函数(NVMCallback),用于在写NVM操作完成后(即数据被写入NVM)执行后续处理。
在步骤1001,任务调度层程序响应于写NVM API(例如,WriteNVM(sec, pba,NVMCallback))被调用,缓存写NVM操作的上下文(例如,上下文包括源地址、目的地址、数据大小、指定的处理函数等),并返回,使得处理任务的代码段可继续执行其他操作。
任务调度层程序响应于访问NVM的硬件资源(例如,介质接口控制器)可用,获取缓存的上下文,向介质接口控制器发送向NVM写入数据的请求。从介质接口控制器接收要写入的数据与写入操作完成有较大的延迟。任务调度层程序在向介质接口控制器发送向NVM写入数据的请求,再次缓存上下文,并在硬件资源可用(介质接口控制器指示向NVM写入数据完成)后(1002),再次获取缓存的上下文,并调用指定的处理函数(NVMCallback)(1020),以缩短延迟。
可选地,处理函数在写入操作出错时执行错误处理。
可选地,写NVM API可指定一段或多段连续或不连续的源地址和/或目的地址,以向NVM的多个位置写入数据。
类似地,处理任务的代码段通过任务调度层程序提供的设置NVM(SetNVM) API对指定的NVM进行设置。任务调度层程序还提供异步操作NVM的其他API。
实施例三
在根据本申请的实施例中,多个任务按一定顺序处理,协同实现任务处理***的功能(例如,处理访问存储设备的IO命令)。为实现功能,需要多次(例如通过出站队列)发送消息以及多次(例如通过入站队列)接收消息。
任务调度层程序提供多种类型的处理函数来处理发送消息与接收消息的操作。通过组合处理函数,实现多种任务处理过程。不同类型的处理函数来适配任务处理***的功能的不同阶段。
作为举例,为实现处理IO命令的功能,需要将其划分为多个阶段,并为各个阶段提供不同类型的函数。示例性地,如图11所示,将其划分为如下几个阶段:(1)接收IO命令(1115);(2)依据IO命令访问NVM芯片(1118);(3) 从NVM芯片获取访问结果(1155);(4)指示IO命令处理完成(1158);以及可选地(5)接收应答(1185)。
第(1)阶段,接收指示IO命令的消息(1115),作为IO命令处理过程的开始。第(2)阶段,为IO命令分配资源(例如,标识IO命令、记录IO命令处理状态),并发出消息,以访问存储设备(1118)。第(3)阶段,接收消息,消息中指示了存储设备访问结果(1155),以及IO命令所使用的资源(从而将所接收的消息指示的IO命令同步骤(2)中的消息指示的IO命令关联)。第(4)阶段,发出指示IO命令处理完成的消息(1158)。可选地,第(5)阶段,接收应答消息(1185),应答消息中指示了第(4)阶段的IO命令处理完成的消息已被正确接收。
与之相应地,提供多类用于接收消息的处理函数以及多类用于发送消息的处理函数。示例性地,第一类用于接收消息的处理函数(PortDriver),所接收的消息中不包括功能的上下文,用于在例如功能的起始阶段接收消息。第二类用于接收消息的处理函数(Generic Driver),所接收的消息中包括功能的上下文,用于在例如功能的中间阶段接收消息。第三类用于接收消息的处理函数(MiniDriver),不能单独使用,而是对第二类用于接收消息的处理函数的扩展,并且在所接收的消息中指示第三类用于接收消息的处理函数。第一类用于发出消息的处理函数,用于处理消息发送过程(GenericDriver)。第二类用于发出消息的处理函数 (GenericDriver+minidriver)用于处理消息发送过程,并且在消息中指示第三类用于接收消息的处理函数。
当然,也可以有其他类型的用于发送消息或接收消息的处理函数。为实现任务处理***的功能,组合使用处理函数的一种或多种。
图11是根据本申请实施例的处理访问存储设备的IO命令的流程图。处理任务的代码段与任务调度层程序运行在任务处理***的CPU之一(记为CPU 0) 上。
响应于入站队列11A出现指示IO命令的消息,在步骤1110,任务调度层程序调用第一类用于接收消息的处理函数。第一类用于接收消息的处理函数作为任务之一或任务的部分,通过获取消息来识别IO命令的内容。在一种实施方式中,任务调度层程序从入站队列中获取消息,并传递给第一类用于接收消息的处理函数。在又一种实施方式中,被调用的第一类用于接收消息的处理函数从入站队列中获取消息。任务调度层程序仅当入站队列中出现消息时,才调用第一类用于接收消息的处理函数,从而第一类用于接收消息的处理函数无须查询或等待入站队列可用。
响应于接收了IO命令(1115),处理任务的代码段为IO命令分配资源,并访问存储设备(1118)。为访问存储设备,向出站队列11B发出消息,以指示任务处理***的其他CPU或控制器对存储设备的NVM芯片进行读/写操作。可选地,处理任务的代码段调用发送(sendMessage)API,来向出站队列发出消息。在步骤1120,任务调度层程序响应于发送(sendMessage)API被调用,注册第二类用于发送消息的处理函数,第二类用于发送消息的处理函数用于发送指示对 NVM芯片进行读/写操作的消息,使得在步骤1130,任务调度层程序依据出站队列状态可调度第二类用于发送消息的处理函数,从而第二类用于发送消息的处理函数被执行时出站队列已经可用,而无须查询或等待出站队列可用。在可选的实施方式中,响应于发送(sendMessage)API被调用,任务调度层程序基于出站队列已经可用,而直接调用第二类用于发送消息的处理函数,而省去注册第二类用于发送消息的处理函数的过程。在第二类用于发送消息的处理函数中,操作出站队列以通过出站队列发出消息,以及可选地,还在消息中指示第三类用于接收消息的处理函数,例如,在消息中添加第三类用于接收消息的处理函数的指针。
任务处理***的其他CPU或控制器读/写NVM芯片,并将对读/写结果的指示通过入站队列发送给图11中运行处理任务的代码段的CPU(CPU 0)。响应于入站队列11C出现指示读/写NVM芯片的结果的消息,在步骤1140,任务调度层程序调用第二类用于接收消息的处理函数。第二类用于接收消息的处理函数作为任务之一或任务的部分,通过获取消息来识别读/写NVM芯片的结果。可选地,在图11的实施例中,第二类用于接收消息的处理函数或任务调度层程序还基于消息的指示,在步骤1150,调用第三类用于接收消息的处理函数。第三类用于接收消息的处理函数作为任务之一或任务的部分对消息进行进一步处理,例如,对存在错误的数据进行恢复。通过在消息中指示调用第三类用于接收消息的处理函数,使得在通过出站队列发出消息时可对消息指定处理函数,提升了消息处理的灵活性。
可选地,响应于接收了指示读/写NVM芯片的结果的消息(1155),处理任务的代码段发出指示IO命令处理完成的消息(1158),向例如主机告知IO命令处理完成。可选地,处理任务的代码段通过调用发送(sendMessage)API,在步骤1160,任务调度层程序响应于发送(sendMessage)API被调用,注册第一类用于发送消息的处理函数,第一类用于发送消息的处理函数用于发送指示IO命令处理完成的消息,使得在步骤1170,任务调度层程序依据出站队列状态可调度第一类用于发送消息的处理函数。在第一类用于发送消息的处理函数中,操作出站队列以通过出站队列11D发出消息。在发出的消息中不包括对第三类用于接收消息的处理函数的指示。以及由于IO命令处理完成,释放为IO命令分配的资源。
可选地,响应于指示IO命令处理完成的消息,IO命令发出方还会给出应答消息,以确认对指示IO命令处理完成的消息的接收。应答消息被填入入站队列。响应于入站队列11E出现应答消息,在步骤1180,任务调度层调用另一第一类用于接收消息的处理函数获取应答消息(1185)。
可选地,任务处理***的功能可包括更多或更少的阶段。各个阶段通过向其他CPU/控制器发出消息或从其他CPU/控制器接收消息来处理任务。对功能的实现由接收消息开始,在实现功能的中间一个或多个阶段,发送消息与接收消息成对出现,在发送消息时可注册接收消息时使用的第二类用于接收消息的处理函数,以及在发出的消息中可添加对接收消息时使用的第三类用于接收消息的处理函数的指示,从而在接收消息时,调用第二类用于接收消息的处理函数,以及可选地第三类用于接收消息的处理函数。可选地,在初始化时为一个或多个入站队列注册第二类用于接收消息的处理函数,以及在发出的消息中添加对接收消息时使用的第三类用于接收消息的处理函数的指示。
任务调度层程序、多种用于接收消息的处理函数与多种用于发送消息的处理函数为实现任务处理***的功能提供了运行环境或框架。实现功能的多个处理任务的代码段通过调用发送(sendMessage)API发送消息,以及向接收队列注册用于接收消息的处理函数。
调用发送(sendMessage)API、用于发送消息的处理函数与用于接收消息的处理函数都不会阻塞处理任务的代码段的执行。发送(sendMessage)API是异步的,用于注册用于发送消息的处理函数。而任务调度层程序根据出站队列/入站队列的状态,仅在资源可用时才调度用于发送消息的处理函数或用于接收消息的处理函数,从而不会阻塞处理任务的代码段的执行。
发送消息的处理函数/用于接收消息的处理函数,向处理任务的代码段屏蔽硬件(例如出站队列/入站队列)操作细节与差异性;使得处理任务的代码段无须关注硬件资源可用性和/或硬件处理的延迟。从而简化了任务处理***的开发,使的任务处理***易于迁移到其他硬件平台。
图12A是根据本申请实施例的优先级加权轮转调度器的框图。任务处理***通常处理多种事件,例如,入站队列中出现待处理的消息,有消息等待通过出站队列发出、用户定义的定时器到时、访问存储器等。根据图12A的实施例的优先级加权轮转调度器对多种事件进行调度,协助或替代根据本申请实施例的任务调度层程序(也参看图2A到图11)选择待处理事件并调用处理任务的代码段进行处理。
被调度的多种事件被分为两类:优先事件与轮转事件。作为举例,诸如入站队列中出现待处理的消息或有消息等待通过出站队列发出的事件属于优先事件,而用户定义的定时器到时事件属于轮转事件。优先事件需要被优先于轮转事件处理。优先事件各自具有优先级,具有高优先级的优先事件被先于具有低优先级的优先事件而处理。依然作为举例,在没有待处理的优先事件时,轮转事件的每个被轮流处理。轮转事件各自具有权重。权重指示轮转事件被轮流处理的频度。例如,具有高权重的事件被处理的频度低于具有低权重的事件。
参看图12A,优先级加权轮转调度器包括使能事件寄存器1210、事件状态寄存器1220、待处理事件寄存器1230、优先事件选择器1240、轮转事件选择器1250、当前轮转事件使能寄存器1260、轮转事件权重表1270、事件仲裁器1280与事件处理函数调用模块1290。作为举例,优先级加权轮转调度器耦合到任务处理***的CPU。CPU可访问使能事件寄存器1210、事件状态寄存器1220、待处理事件寄存器1230和/或当前轮转事件使能寄存器1260,配置轮转事件选择器1250、当前轮转事件使能寄存器1260和/或事件仲裁器1280的工作策略,更新或读取轮转事件权重表。优先级加权轮转调度器的事件处理函数调用模块1290通过例如设置CPU的程序计数器以指示CPU调用处理任务的代码段。
使能事件寄存器1210的每个比特用于指示对应的事件是否被使能。事件被使能指在该事件出现时,允许对该事件进行处理。若事件寄存器1210的比特指示对应的事件未被使能,则即使该事件出现,也不对该事件进行处理。CPU通过设置使能事件寄存器1210来屏蔽一个或多个事件,以不对这些事件进行处理。
事件状态寄存器1220的每个比特用于指示对应的事件是否出现。例如,队列中出现待处理的消息,作为响应,事件状态寄存器1220同该队列对应的比特被设置。作为又一个例子,CPU设置事件状态寄存器1220来指示出现了一个或多个事件。
待处理事件寄存器1230的每个比特指示对应的事件是否已出现且被使能。从而,优先级加权轮转调度器仅对已出现且被使能的事件进行处理,而不处理未出现或虽已出现但未被使能的事件。例如,事件状态寄存器1220的每个比特,指示使能事件寄存器1210与事件状态寄存器1220的对应比特相“与”的结果。
作为举例,任务处理***处理40种事件,使能事件寄存器1210、事件状态寄存器1220以及待处理事件寄存器1230各自包括40比特,每比特同被处理的 40种事件一一对应。
优先事件选择器1240耦合到待处理事件寄存器1230中指示优先事件的比特,并输出对优先事件之一的指示,以选择该优先事件。作为举例,优先事件选择器1240依据待处理事件寄存器1230的指示优先事件的有效比特(指示已出现且被使能的优先事件),选择具有最高优先级的事件,并提供给事件仲裁器1280。
轮转事件选择器1250耦合到待处理事件寄存器1230中指示轮转事件的比特,并输出对轮转事件之一的指示,以选择该轮转事件。作为举例,轮转事件选择器1250依次处理多个轮转事件,或者按指定的频度依次处理多个轮转事件。
根据图12A的实施例,轮转事件选择器1250,依据当前轮转事件使能寄存器1260的指示,从已出现且被前轮转事件使能寄存器1260使能的事件中选择一个,并提供给事件仲裁器1280。前轮转事件使能寄存器1260依据轮转事件的权重,设置对应于各个轮转事件的比特,以指示轮转事件被使能。在一个例子中,轮转事件具有相同的权重,优先级加权轮转调度器初始化后,当前轮转事件使能寄存器1260指示每个轮转事件都被使能。事件仲裁器1280选择一个轮转事件被处理后,告知当前轮转使能寄存器1260。作为响应,当前轮转事件使能寄存器 1260清除对应于被处理的轮转事件的比特,从而该被处理的轮转事件暂时不会再被处理。进一步地,响应于当前轮转事件使能寄存器1260的比特对应的轮转事件都被处理,当前轮转事件使能寄存器1260的所有比特被清除,当前轮转事件使能寄存器1260再次被设置为指示每个轮转事件都被使能。
事件仲裁器1280从优先事件仲裁器1240与轮转事件仲裁器1250指示的事件中,选择其中一个进行处理。在一个例子中,为了优先处理优先事件,当优先事件仲裁器1240与轮转事件仲裁器1250都指示有事件待处理时,事件仲裁器 1280选择优先事件仲裁器1240指示的事件;仅当优先事件仲裁器1240未指示待处理事件,而轮转事件仲裁器1250指示待处理事件时,才处理轮转事件仲裁器 1250指示的事件。进一步地,事件仲裁器1280提供优先级反转或防饿死机制,响应于轮转事件仲裁器1250指示的事件长期得不到处理,而临时地相对于优先事件仲裁器1240指示的事件而优先地处理轮转事件仲裁器1250指示的事件。
事件仲裁器1280将选择的被处理事件提供给事件处理函数调用模块1290,由事件处理函数调用模块1290根据事件调用对应的处理任务的代码段对事件进行处理。例如,事件处理函数调用模块1290根据事件仲裁器1280提供的事件索引,访问处理函数表(参看图3),获得并调用对应于事件的处理任务的代码段。作为又一个例子,在入站队列的消息中指示处理任务的代码段,事件处理函数调用模块1290根据事件仲裁器1280提供的事件索引,指示将入站队列的待处理的消息的指定字段,作为处理任务的代码段的入口地址,并调用该处理任务的代码段。依然可选地,入站队列的消息通过指定字段指示处理任务的代码段的入口地址的提供机制,选择由处理函数表提供入口地址还是由入站队列的消息的指定字段提供入口地址,以及事件处理函数调用模块1290将指定的入口地址设置给 CPU的程序计数器。在依然又一个例子中,事件处理函数调用模块1290从处理函数表获取处理任务的代码段的处理地址,而该处理任务的代码段被调用后,还从入站队列的消息的指定字段获取又一处理任务的代码段的入口地址并调用该又一处理任务的代码段。
可选地,CPU设置处理任务的代码段的入口地址在入站队列的消息中的位置 (例如,相对消息起始地址的偏移值)。依然可选地,由消息发出方,在入站队列的消息头部的指定位置,描述消息是否携带了处理任务的代码段的入口地址以及该入口地址在消息中的位置。
作为又一个例子,在出站队列的消息中指示处理任务的代码段,事件处理函数调用模块1290根据事件仲裁器1280提供的事件索引,指示将出站队列的待处理的消息的指定字段,作为处理任务的代码段的入口地址,并调用该处理任务的代码段。可选地,CPU设置处理任务的代码段的入口地址在出站队列的消息中的位置(例如,相对消息起始地址的偏移值)。依然可选地,由消息发出方,在出站队列的消息头部的指定位置,描述消息是否携带了处理任务的代码段的入口地址以及该入口地址在消息中的位置。
作为又一个例子,轮转事件权重表部件1270向当前轮转事件使能寄存器1260提供应当被使能的事件。图12B与图12C是轮转事件权重表部件1270所存储的轮转事件权重表。参看图12B,有3个轮转事件(分别记为E1、E2与E3) 待处理,其中轮转事件E1的权重最低,轮转事件E2的权重次低,而轮转事件 E3的权重最高。图12B中,字母“Y”指示对应列表头的事件被使能,而字母“N”指示对应列表头的事件被禁用。轮转处理事件E1、事件E2与事件E3。事件E1 每轮都被处理,事件E2每隔1轮被处理一次,事件E3每隔2轮被处理一次。轮转事件权重表部件1270每次将图12B的一行提供给当前轮转事件使能寄存器 1260,在处理完一轮后,箭头移向图12B的下一行。在每1轮事件处理中,所有 3个轮转事件都有机会得到最多一次处理;若在准备处理轮转事件时,对应的事件未出现,则该轮中不再对其进行处理。
作为举例,在初始化后,箭头指向图12B的轮转事件权重表的第1行。该轮中,将图12B的第1行提供给当前轮转事件使能寄存器1260,指示事件E1、事件E2与事件E3都被使能。依然作为举例,待处理事件寄存器1230指示事件E1 出现、事件E2未出现而事件E3出现。轮转事件选择器1250根据事件是否出现以及当前轮转事件使能寄存器1260指示的事件使能状态选择事件之一。例如,由于事件E1出现,且被使能,轮转事件选择器1250选择事件E1提供给事件仲裁器1280。事件仲裁器1280选择事件E1处理后,告知当前轮转事件使能寄存器1260,清除对事件E1的使能,从而在当前轮中,即使事件E1再次出现,轮转事件选择器1250也不再选择事件E1。依然作为举例,接下来,由于事件E2 未出现,轮转事件选择器选择事件E3(已被使能)提供给事件仲裁器1280。事件仲裁器1280响应于选择事件E3处理后,告知当前轮转事件使能寄存器1260,清除对事件E3的使能。以及响应于轮转事件选择器1250对所有3种事件进行了一轮选择(事件E1与事件E3被处理,而事件E2未被出现),轮转事件权重表部件1270的箭头移向下一行(例如,第2行),将图12B的第2行内容提供给当前事件轮转使能寄存器。在图12B的第2行中,仅事件E1被使能,而事件E2 与事件E3未被使能,从而图12B的各个行,体现了各事件的权重,使得,对轮转事件的每轮处理中,事件E1都被使能,而每隔1轮,事件E2被使能一次,每隔2轮,事件E3被使能一次。被使能的事件在当前轮中,若出现,则会被处理。被使能的事件在当前轮中,若未出现,则丧失在当前轮被处理的机会。
图12C是轮转事件权重表的又一个例子。有4个轮转事件(分别记为E0、 E1、E2与E3)待处理。事件E1权重最低,每轮都有机会被处理。事件E2权重次低,每隔1轮有机会被处理。事件E3权重次高,每隔2轮有机会被处理。事件E3权重最高,每隔3轮有机会被处理。初始化后,图12C的第1行被提供给当前轮转事件使能寄存器1260,从而事件E0与事件E1被使能,而事件E2与事件E3被禁止。在一轮中,若事件E0与事件E2出现,则轮转事件选择器1250 将事件E0提供给事件仲裁器1280,事件E2不被处理,而事件E1因未被使能而丧失了在本轮被处理的机会。响应于事件E0被处理,当前轮转事件使能寄存器 1260中对应于事件E0的比特被清除(以指示事件E0被禁用)。响应于当前轮中对所有轮转事件都进行了检查(虽然仅事件E0被处理),轮转事件权重表的箭头指向下一行(第2行),并将第2行的内容提供给当前轮转事件使能寄存器1260。
若轮转事件权重表的箭头指向表的最后一行,在下一轮中,箭头回绕指向表的第1行。
可选地,CPU设置诸如图12B或图12C的轮转事件权重表。
图13是根据本申请又一实施例的优先级加权轮转调度器的框图。根据图13 的实施例的优先级加权轮转调度器对多种事件进行调度,协助或替代根据本申请实施例的任务调度层程序(也参看图2A到图11)选择待处理事件并调用处理任务的代码段进行处理。
同图12展示的优先级加权轮转调度器类似,图13的优先级加权轮转调度器包括使能事件寄存器1310、事件状态寄存器1320、待处理事件寄存器1330、优先事件选择器1340、轮转事件选择器1350、当前轮转事件使能寄存器1360、轮转事件权重表1370、事件仲裁器1380与事件处理函数调用模块1390。
图13的优先级加权轮转调度器还包括耦合到事件处理函数调用模块1390的处理函数表部件1392。可选地,事件处理函数调用模块1390还耦合到入站队列的消息存储部件1394。可选地,事件处理函数调用模块1390依据事件仲裁器指示的事件,从处理函数表中获取处理任务的代码段的入口地址,并调用对应的处理任务的代码段。依然可选地,事件处理函数调用模块1390依据事件仲裁器指示的事件(例如,事件指示入站队列有待处理的消息),访问同事件对应的入站队列的消息存储部件1394,从消息中获取处理任务的代码段的入口地址,并调用对应的处理任务的代码段。对于指示有消息待通过出站队列发出且出站队列未满的事件,事件处理函数调用模块1390获取同事件对应的处理任务的代码段,以及可选地,还获取待发出的消息并提供给处理任务的代码段。依然可选地,由处理任务的代码段查询和/或获取待发出的消息。
可选地,处理任务的代码段被调用后,通过关闭部件1396暂时地关闭事件处理函数调用模块1390,以顺序处理事件,避免处理任务的代码段在处理事件期间被打断。以及在处理任务的代码段结束之前,打开事件处理函数调用模块1390,以允许事件处理函数调用模块1390调用其他处理任务的代码段。
作为举例,优先级加权轮转调度器耦合到任务处理***的CPU。CPU可访问使能事件寄存器1310、事件状态寄存器1320、待处理事件寄存器1330和/或当前轮转事件使能寄存器1360,配置轮转事件选择器1350、当前轮转事件使能寄存器1360、轮转事件权重表1370和/或事件仲裁器1380的工作策略。
轮转事件选择器1350耦合到待处理事件寄存器1330,并输出对轮转事件之一的指示,以选择该轮转事件。轮转事件选择器1350,依据当前轮转事件使能寄存器1360的指示,从已出现且被前轮转事件使能寄存器1360使能的事件中选择一个,并提供给事件仲裁器1380。事件仲裁器1380选择一个轮转事件被处理后,告知当前轮转使能寄存器1360。作为响应,当前轮转事件使能寄存器1360清除对应于被处理的轮转事件的比特。进一步地,响应于当前轮转事件使能寄存器 1360的被使能比特对应的轮转事件都被处理(或对应事件未出现),轮转事件使能设置部件1372用轮转事件权重寄存器1374的值设置当前轮转事件使能寄存器 1360。
轮转事件权重表1370记录每种轮转事件的权重。作为举例,有3个轮转事件(分别记为E0、E1与E2)待处理。事件E0权重最低,每轮都有机会被处理。事件E1权重次低,每隔1轮有机会被处理。事件E2权重最高,每隔2轮有机会被处理。在轮转事件权重表1370中分别每种轮转事件的权重值,例如,对应于事件E0、E1与E2,权重值分别为0、1与2。响应于例如事件E0被事件仲裁器 1380指示处理(或处理完成),轮转事件使能设置部件1372从轮转事件权重表 1370获取事件E0对应的权重值(0),根据权重值,将事件E0设置在轮转事件权重寄存器1374、1376与1378之一中,以指示该事件下次被使能的时机。图13 的例子中,轮转事件有3种权重值,对应地,设置同权重值数量相同的轮转事件权重寄存器。每个轮转事件权重寄存器包括多个比特,每个比特对应轮转事件之一。作为举例,响应于被处理事件(E0)的权重为0,在轮转事件权重寄存器1374 的中设置对应于事件E0的比特;响应于被处理事件E1的权重为1,在轮转事件权重寄存器1376的中设置对应于事件E1的比特;响应于被处理事件E2的权重为2,在轮转事件权重寄存器1378的中设置对应于事件E2的比特。
响应于轮转事件选择器1350对所有3种事件进行了一轮选择(被使能且出现的事件被处理、未被使能或未出现的事件不被处理),轮转事件使能设置部件 1372将轮转事件权重寄存器1374设置给当前轮转事件使能寄存器1360,以及将轮转事件权重寄存器1376设置给轮转事件权重寄存器1374,将轮转事件权重寄存器1378设置给轮转事件权重寄存器1376。以及将轮转事件权重寄存器1378 清空。可选地,轮转事件权重寄存器1374、1376与1378实现为移位寄存器,使得轮转事件权重寄存器1376的值通过移位被传递给轮转事件权重寄存器1374,而轮转事件权重寄存器1378的值同时通过移位被传递给轮转事件权重寄存器 1376。
作为又一个例子,有4个轮转事件(分别记为E0、E1、E2与E3)待处理。事件E0权重最低,每轮都有机会被处理。事件E1权重次低,每隔1轮有机会被处理。事件E2权重次高,每隔2轮有机会被处理。事件E3权重最高,每隔3 轮有机会被处理。由于事件有4种权重,或者权重指示的轮转间隔有4种,设置依次排列的4个轮转事件权重寄存器(分别记为R0、R1、R2与R3)。每处理一轮事件,轮转事件使能设置部件1372将轮转事件权重寄存器R0设置给当前轮转事件权重寄存器1360,而用排列在后的轮转事件权重寄存器的值设置排列在前的轮转事件权重寄存器(例如,将寄存器R1设置给寄存器R0,将寄存器R2设置给寄存器R1)。在每轮事件处理期间,响应于事件(例如E1)被处理或处理完成,将当前轮转事件使能寄存器1360中对应于事件(E1)的比特清除,根据轮转事件权重表1370指示的事件(E1)权重,设置同权重排序对应的轮转事件权重寄存器(R1)中指示事件(E1)的比特。
作为又一个例子,有4个轮转事件(分别记为E0、E1、E2与E3)待处理。事件E0权重最低,每轮都有机会被处理。事件E1权重次低,每隔1轮有机会被处理。事件E2权重次高,每隔2轮有机会被处理。事件E3权重最高,每隔5 轮有机会被处理。依据权重指示的轮转间隔有5种,设置依次排列的5个轮转事件权重寄存器(分别记为R0、R1、R2、R3与R4)。在每轮事件处理期间,响应于事件(例如E4)被处理或处理完成,将当前轮转事件使能寄存器1360中对应于事件(E4)的比特清除,根据轮转事件权重表1370指示的事件(E4)权重,设置同权重排序对应的轮转事件权重寄存器(R4)中指示事件(E4)的比特。
在根据本申请的一个实施例中,入站队列中出现待处理的消息被定义为优先级事件,而用户注册的事件属于轮转事件。可选地,任务处理***初始化时,CPU 设置入站队列和/或用户注册的事件与事件状态寄存器1220的比特的对应关系。进一步可选地,CPU还设置同事件对应的用于处理任务的代码段及其入口地址。例如,通过注册(Register)API为一个或多个事件注册处理函数(也称为,用于处理任务的代码段)。作为响应,事件及其关联的处理函数被记录在处理函数表中。
进一步可选地,CPU设置优先级事件的优先级和/或轮转事件的权重。
任务处理***运行期间,响应于入站队列中出现待处理的消息,事件状态寄存器1220(参看图12)的对应比特被设置。响应于用户注册的事件被触发(例如,定时器到时),事件状态寄存器1220的对应比特被设置。优先级加权轮转调度器对多个事件进行调度,从多个出现的事件中选择其中之一,设置CPU的程序计数器为对应所选择事件的处理任务的代码段的入口地址。所选择事件被处理完成后,优先级加权轮转调度器选择另一待处理事件。从而,CPU设置对多个事件的调度策略,而无须干预调度过程,分担了CPU的负载。
在根据本申请的又一个实施例中,入站队列中出现待处理的消息被定义为优先级事件,有消息等待通过出站队列发出且出站队列未满被定义为优先级事件,而用户注册的事件属于轮转事件。可选地,任务处理***初始化时,CPU设置入站队列、出站队列和/或用户注册的事件与使能事件寄存器1210/事件状态寄存器 1220的比特的对应关系。任务处理***运行期间,响应于入站队列中出现待处理的消息,事件状态寄存器1220(参看图12A)的对应比特被设置;响应于出站队列未满,使能事件寄存器1210的对应比特被设置,响应于有消息等待通过出站队列发出,事件状态寄存器1220的对应比特被设置,响应于用户注册的事件被触发(例如,定时器到时或者用户注册的事件被处理完成),事件状态寄存器1220 的对应比特被设置。优先级加权轮转调度器对多个事件进行调度,从多个出现的事件中选择其中之一,设置CPU的程序计数器为对应所选择事件的处理任务的代码段的入口地址。
以上所述,仅为本发明的具体实施方式,但本发明的保护范围并不局限于此,任何熟悉本技术领域的技术人员在本发明揭露的技术范围内,可轻易想到变化或替换,都应涵盖在本发明的保护范围之内。因此,本发明的保护范围应以所述权利要求的保护范围为准。