RTEMS:多处理器系统管理
23.1: 介绍
%A
%A 多处理器实时系统,对传统的实时系统提出了很多新的需求, 例如在多个处理器间共享数据和全局资源。此外,多个处理器协同的工作方式也影响了实时系统的每个方面,使系统的复杂性大为增加。
%A
%A 为了解决多处理器系统的问题,RTEMS提供了一系列灵活有效的机制。RTEMS目前支持的多处理器系统不但包括传统的紧耦合系统与松耦合系统,还对混合耦合系统、异构系统以及混合异构系统都提供了强有力的支持。
%A
%A RTEMS 的一个重要设计目标是超越目标硬件的硬件边界。该目标的实现方法是为应用软件提供了一个目标硬件系统的逻辑视图,在视图中各个处理器是透明的。因此应用软件开发者可以将包括任务、队列、事件、消息、信号量和内存块这样一些对象设计为全局对象。各个处理器节点上的任务可以访问这些全局变量。RTEMS 自动判断被存取的对象处于本地节点上还是处于其他处理器上。简单的说,RTEMS允许整个多处理器系统的软硬件在逻辑上表现为一个系统。
%A 23.2.1 : 处理器结点
%A
%A RTEMS 系统中一个处理器字系统被称为一个系统结点。每个结点将会由应用设计者分配一个唯一的结点编号。一般来说RTEMS节点的编号是从1开始的连续整数。节点编号、结点、和最大结点数目maximum_nodes都在多处理器节点配置表中定义。maximum_nodes的数值以及全局对象数目 maximum_global_objects都应该根据系统需要尽可能的小。
%A
%A 在进行多处理器操作时,节点编号被RTEMS用来区别不同的节点。因此,多处理器通信层(MPCI)必须能以节点编号为基础进行消息路由。
%A 23.2.2 : 全局对象
%A
%A 所有使用GOBAL属性创建的RTEMS对象将会在系统中所有的节点上注册。虽然使用全局节点和本地节点相比有一些限制,但是全局对象可以被所有的节点访问。而且访问全局对象的任务本身可以不用是全局的。全局对象的数目被多处理器配置表中的maximum_global_objects所限制。任务在多个处理器上的分派在系统设计时由程序员实现。目前系统还不支持任务在多个处理器上的动态自动分配。
%A 23.2.3 : 全局对象表
%A
%A 对于多处理器的RTEMS系统来说,RTEMS维护了二个存放对象信息的表格: 一个本地对象表格和一个全局对象表格。节点上的本地对象表存放了在该结点上创建的所有对象的信息(包括本地上创建的全局对象信息)。全局对象表中包含了系统中的所有全局对象信息。
%A
%A 系统中每个结点上都会维护一个相同的全局对象表。为了使该表能动态更新并且保持一致,每个动态对象创建和销毁的时候,都会向系统中所有节点发布信息。
%A 23.2.4 : 远程调用
%A
%A 当一个应用对远程节点上的全局对象上进行操作时,RTEMS将产生一个远程请求 (RQ) 消息并且将其送到对应的结点。在完成对应的操作后,在完成对应操作后,远程节点将会构建远程响应 (RR) 消息,然后将其发送回请求节点。 对于将会产生副作用的的函数 (例如删除全局变量的任务)被称为远程进程 (RP),RP并不需要接收结点对请求作出答复。
%A
%A 对于远程操作,处理执行时间比本地的操作略微长一些以外,其他并没有什么大的区别。由于RTMES屏蔽了底层通信的细节,所以应用层并不知道对应的操作是否在本地节点上完成。对于远程通信的开销主要取决于通信的手段,此外和MPCI层的效率也有一些关系。
%A
%A 下面是远程操作的基本流程:
%A
%A • 应用向远程的全局对象发出函数请求,
%A
%A • RTEMS 判断对象所在的结点。
%A
%A • RTEMS 调用用户提供的 MPCI 例程 GET_PACKET 构建RQ 消息包。
%A
%A • 构建消息包后,RTEMS 调用用户提供的 MPCI 例程 SEND_PACKET 发送消息包到对象所在结点 ( 目的结点) 。
%A
%A • 远程调用的发起者将会被阻塞,直到 RR 消息返回,阻塞期间,处理器将执行其他任务。
%A
%A • 在目的地结点上的 MPCI 层发现消息包( 一般在ISR中) 抵达,就调用 rtems_multiprocessing_announce 函数。 该函数将多重处理服务器就绪。
%A
%A • 多重处理服务器调用用户提供的 MPCI 例程 RECEIVE_PACKET,运行被请求的操作,构建一个 RR 消息, 然后将其返回给调用结点。
%A
%A • 在调用结点上的 MPCI 层探测到消息包(一般是通过中断完成), 然后调用 RTEMS的rtems_multiprocessing_announce 函数。 该函数让多重处理服务器就绪。
%A
%A • 多重处理服务器调用用户提供的 MPCI 例程 RECEIVE_PACKET,使被阻塞的请求任务就绪, 并且将自己阻塞,直到另外的一个消息包到达,控制转到调用者任务。
%A
%A 如果一个无法修正的错误在用户提供的 MPCI 层中发生,异常处理函数将被启动。一般来说RTEMS中的MPCI为消息传输和接收提供可靠保证,所以错误产生几率非常小。
%A 23.2.5 : 代理
%A
%A 代理是驻留在远程节点上的 RTEMS 数据结构,RTEMS使用该结构来代表被阻塞的远程操作。远程调用使用rtems_semaphore_obtain 或者 rtems_message_queue_receive 函数而被阻塞时,RTEMS将会为被阻塞的任务创建代理。如果对象是本地对象,可以通过操纵本地任务的任务控制块来表明该任务因为信号量或者消息被阻塞。然而,对于远程任务,操作就不同了。任务控制块只驻留在在任务所在的节点上,因此,远程节点必须为在其上执行的外来任务分配数据结构来代表这个任务,这就是代理。
%A
%A 代理数目的最大值在多处理器配置表格中定义。系统中每个节点可以使用不同的代理数最大值。代理控制块的分布是应用相关的,随着任务分布不同而不同。
%A 23.2.6 : 多处理器配置表
%A
%A 多处理器系统中,多处理器配置表包含 RTEMS 需要的系统配置信息。 该表格在后面对应的章节还有详细介绍。
%A
%A
%A
%A 多处理器通信接口与移植
%A
%A 作者 Ray
%A
%A RTEMS版权所有,转载请注明来源www.rtems.net,作者ray@rtems
%A 23.3: 多处理器通信接口层
%A
%A 多处理器通信接口层 (MPCI) 是一组用户提供的函数过程。这些函数允许多处理器系统中相互通信。这些函数用来准备和处理各种RTEMS远程请求。如果中断被屏蔽,那么当MPCI激活时中断也会激活。如果任务执行模式和中断等级被MPCI层修改,在MPCI执行完毕后,他们会恢复到原始状态。
%A
%A MPCI层负责管理数据包的缓存池,并且在节点间传输数据包。包含消息包信息数据包在节点间传输。通常MPCI层封装数据包时,会将MPCI层所需要的信息放入包头。
%A
%A MPCI层中用户例程将会放入多处理器通信接口表中。用户必须为接口表提供下面的函数入口:
%A
%A • initialization 初始化 MPCI函数
%A
%A • get_packet 为消息包分配缓存
%A
%A • return_packet 释放消息包缓存
%A
%A • send_packet 发送消息包给另外一个结点
%A
%A • receive_packet 消息包接收
%A
%A 在下列情形下RTEMS将发送消息包:
%A
%A • 发起者节点上产生RQ时;
%A
%A • 目标节点产生RR时;
%A
%A • 创建全局对象时;
%A
%A • 删除全局对象时;
%A
%A • 在远程节点上被阻塞本地任务正被删除时;
%A
%A • 系统初始化进行系统一致性检查时
%A
%A 如果目标硬件支持,目标节点接收到数据包时会产生中断。否则,需要使用实时时钟ISR定期检查是否有数据包到达。无论使用哪种方式,在检测到数据包时,会调用rtems_multiprocessing_announce 函数发布数据包到达的信息。在离开 ISR 之后,控制将会传给多处理服务器处理消息包。多处理服务器将会调用 get_packet 获取消息包缓存,然后使用receive_entry 将消息复制到缓存中。
%A
%A
%A 23.3.1 : INITIALIZATION-初始化
%A
%A 在 rtems_initialize_executive 函数中初始化 MPCI 层和相关硬件的时候,会调用MPCI层的中初始化函数。所有的设备驱动初始化之后,将会调用MPCI的初始化函数。下面是函数的原型:
%A
%A
%A
%A rtems_mpci_entry user_mpci_initialization(
%A
%A rtems_configuration_table *configuration
%A
%A );
%A
%A
%A
%A 这里 , configuration 参数是用户配置表的地址 ; 只有初始化工作完成后 , 才能对全局对象进行操作。从运行到系统结束,INITIALIZATION只会调用一次。如果初始化失败,将会使用异常处理函数处理。
%A
%A MPCI 层的主要功能之一是为RTEMS提供信息包缓冲器。INITIALIZATION例程需要为消息预分配消息包缓存池。使用缓存池,就可以提高RTEMS反应速度,并保证无论何时都有可用缓存区用于存储新的信息。
%A 23.3.2 : GET_PACKET
%A
%A 当RTEMS需要包缓存来发送或者广播消息时,需要使用用户提供的 MPCI 层GET_PACKET函数获取缓存。 GET_PACKET 的原型是 :
%A
%A
%A
%A rtems_mpci_entry user_mpci_get_packet(
%A
%A rtems_packet_prefix **packet
%A
%A );
%A
%A
%A
%A 这里packet是指向包地址的指针。由于RTEMS使用了预分配缓存池的策略,所以该函数总是能成功获取包缓存区。如果因为系统异常导致无法获取缓存区,那么,将会调用系统的异常处理函数。
%A
%A 为了避免每次收到包时就获取数据缓存,RTEMS为GET_PACKET做了优化。比如,RTEMS发送应答信息(RR)回发起者时,将会复用请求信息(RQ)使用的数据缓存。
%A
%A
%A 23.3.3 : RETURN_PACKET
%A
%A 当 RTEMS 要释放空闲消息包缓冲区时 , 将调用用户提供的 MPCI 层 RETURN_PACKET 。 下面是函数的原型:
%A
%A
%A
%A rtems_mpci_entry user_mpci_return_packet(
%A
%A rtems_packet_prefix *packet
%A
%A );
%A
%A packet是数据缓存区的地址。如果消息包释放失败,将产生一个异常。
%A 23.3.4 : RECEIVE_PACKET
%A
%A MPCI的数据包到达后,如果RTEMS需要对其进行处理,则先使用MPCI 层的 RECEIVE_PACKET 函数。函数的原型如下:
%A
%A
%A
%A rtems_mpci_entry user_mpci_receive_packet(
%A
%A rtems_packet_prefix **packet
%A
%A );
%A
%A
%A
%A 这里packet是指向消息包存放地址的指针。如果有消息包,那么packet包含了信息的地址,如果没有消息包,那么packet=MULL。
%A 23.3.5 : SEND_PACKET
%A
%A 当 RTEMS 需要向其他节点传输信息数据包时,就会调用用户提供的 MPCI 层的 SEND_PACKET 分量。该分量原型如下:
%A
%A
%A
%A rtems_mpci_entry user_mpci_send_packet(
%A
%A rtems_unsigned32 node,
%A
%A rtems_packet_prefix **packet
%A
%A );
%A
%A
%A
%A 这里,node是目标节点编号,packet是指向信息包存放的地址的指针。如果消息包发送失败,将会产生异常。
%A
%A 如果node是0,那么表示消息是广播消息,将广播到系统其他所有的结点。虽然一些 MPCI 层是基于支持广播的通信媒体上创建的,如果通信层不支持广播,则需要将数据包分别发送到所有节点。
%A
%A 许多 MPCI 层数据包 rtems_packet_prefix 结构中 packet_length 字段避免传输不必要的数据。这对于传输媒体带宽比较窄时很重要。
%A
%A 在异构系统中,MP_packet_prefix结构中的to_convert 字段指出有多少数据包需要进行转换(例如大端小端转换)。
%A 23.3.6 : 异构(Heterogenous)环境
%A
%A 异构环境指的是系统中有不同种类的处理器。为异构系统开发MPCI 层需要完全理解系统中处理器的差别。其中一个问题就是大端(big endian)小端(little endian)的问题。这里大端小端指的是不同处理器中数据的存储表示方案(组成一个数据实体字节次序)。对于32位处理器,数据长度为4字节,把低位字节放在物理地址的低位的处理器被归类为小端处理器。 小端字节排序如下所示:
%A
%A
%A
%A +---------------+----------------+---------------+----------------+
%A | | | | |
%A | 字节 3 | 字节 2 | 字节1 | 字节 0 |
%A | | | | |
%A +---------------+----------------+---------------+----------------+
%A
%A
%A
%A 相反地,把高位字节放在物理地址的低位的处理器被归类为大端处理器。 大端的字节排序如下所示:
%A
%A +---------------+----------------+---------------+----------------+
%A | | | | |
%A | 字节 0 | 字节 1 | 字节2 | 字节 3 |
%A | | | | |
%A +---------------+----------------+---------------+----------------+
%A
%A 为了在大端和小端处理器间传输数据,程序员一般使用一种公用的格式来减少数据转换的工作,减小不必要的开销。
%A
%A 共享数据时另一个需要解决的问题是数据结构对齐的问题。数据的对齐不但和处理器相关还和编译器相关。例如有的处理器允许数据元素以字节的方式对其,有些处理器则有严格的对齐其规则。对于32位处理器,常见的规则是使用半字对齐(两字节对齐)或者字对齐(四字节对齐)。如果违反这些规则轻则影响性能,重则会产生处理器异常。
%A
%A 共享数据兼容的其他问题包括浮点数的表示,十进位的数据和字符串表示等。 除此之外,负数是使用什么补码策略。这些因素联合增加设计的复杂性,而且操纵数据结构在处理器之间分享。
%A
%A 为了解决上面提到的数据兼容性问题,RTEMS中的数据包进行了特别的设计。数据包允许程序员能够方便的对其进行数据格式转换而不需要知道包的低层信息。此外还尽可能的减少了不必要的开销。对于MPCI 层的数据包转换,程序员应该注意下面的问题:
%A
%A 所有的数据包基于四字节对齐。
%A
%A 数据包包含了RTEMS和应用数据组成。
%A
%A 所有的 RTEMS 数据被当做32位无符号数进行处理。并且将放到信息包的RTEMS_MINIMUM_UNSIGNED32S_TO_CONVERT元组中。
%A
%A 消息包中RTEMS 数据分量原始的endian格式中。 大小端转换可能通过MPCI层的消息发送方或者接收方来完成。
%A
%A RTEMS并为对应用程序数据做任何假设。
%A 23.4.1 : 发布信息包
%A
%A MPCI层调用rtems_multiprocessing_announce 函数通知RTEMS一个信息包已经从其他结点送到本地。该函数可以从中断服务例程ISR或者轮询例程中调用。
%A
%A 函数原型:
%A
%A void rtems_multiprocessing_announce( void);
%A
%A 该函数将会引起抢占式调度,但是该函数不会在远程结点上产生活动。
%A%A
%A
*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。