AUTOSAR_SWS_ExecutionManagement_R2011
AUTOSAR_SWS_ExecutionManagement
7 功能规范
执行管理是自适应平台基础中的一个功能集群。执行管理负责系统执行管理的所有方面,包括平台初始化和应用程序的启动/关闭。
执行管理与操作系统协同工作。特别是,执行管理负责配置操作系统以执行应用程序的运行时调度和资源监控。
本章描述了执行管理的功能行为。
- 第7.2节介绍了执行管理中的关键术语,重点关注应用程序、可执行文件和建模进程之间的关系。后者指的是描述进程的元模型实例,它最终将实现为操作系统进程。
- 第7.3节涵盖了执行管理的核心运行时职责,包括应用程序的启动。
- 第7.4节描述了应用程序的生命周期,包括建模进程状态转换和启动/关闭序列。
- 第7.5节涵盖了与执行管理中状态管理相关的多个主题,包括执行、机器和功能组状态管理。
- 第7.6节记录了执行管理确定性执行提供的支持,使得在给定相同输入和内部状态的情况下,计算始终产生相同的输出。
- 第7.7节描述了执行管理如何支持资源管理,包括限制应用程序对CPU和内存的使用。
- 第7.8节概述了容错策略。本节将在未来版本中扩展,以描述如何在执行管理内实现这些策略。
- 第7.9节涵盖了可信平台的主题,即确保应用程序的完整性和真实性。
7.1 功能集群生命周期
7.1.1 启动
参见第7.5.2.1节。
7.1.2 关闭
参见第7.5.2.2节。
7.1.3 重启
参见第7.5.2.2节。
7.2 技术概述
本章简要总结了应用程序、可执行文件和建模进程之间的关系。
7.2.1 应用程序
应用程序是为了解决一组连贯的功能需求而开发的。一个应用程序由可执行的软件单元、其他与执行相关的项(例如数据或参数文件)以及用于集成和执行的描述性信息(例如基于AUTOSAR元模型的形式化模型描述、测试用例等)组成。
应用程序可执行文件可以位于中间件之上的用户层,或者可以实现AUTOSAR自适应平台的功能集群(位于中间件层),参见[4]中的[constr_1605]。
一般来说,无论是用户级还是平台级的应用程序,执行管理都一视同仁,并且可以使用操作系统以及AUTOSAR自适应平台其他功能集群提供的所有机制和API。然而,这样做可能会限制其在其他AUTOSAR自适应平台实现上的可移植性。
7.2.2 自适应应用程序
自适应应用程序是一种特定类型的应用程序。自适应应用程序的实现完全符合AUTOSAR规范,即它仅限于使用AUTOSAR标准化的API,并且需要遵循特定的编码指南,以允许在不同的AUTOSAR自适应平台实现之间进行重新分配。
自适应应用程序始终位于中间件之上。为了实现可移植性和重用,只要技术上可行,用户级应用程序应为自适应应用程序。
自适应应用程序是功能开发的结果,并且是针对特定机器配置和集成的交付单元。一些合同(例如关于所用库的合同)以及与其他自适应应用程序交互的服务接口需要事先达成一致。详细信息参见[10]。
7.2.3 可执行文件
可执行文件是应用程序的一部分的软件单元。它只有一个入口点(main函数)[SWS_OSI_01001]。一个应用程序可以由一个或多个可执行文件实现[TPS_MANI_01010]。
可执行文件的生命周期通常包括:
| 流程步骤 | 软件元信息 |
|---|---|
| 开发和集成 | 用于部署到目标机器的链接、配置和校准的二进制文件。该二进制文件可能包含集成时生成的代码。 |
| 执行清单,参见7.2.5和[4],以及服务实例清单(执行管理不使用)。 |
表7.1:可执行文件生命周期
属于同一自适应应用程序的可执行文件可能需要部署到不同的机器,例如,部署到一个高性能机器和一个高安全机器。
图7.2显示了可执行文件从部署到执行的生命周期。
7.2.4 建模进程
建模进程是可执行文件的一个实例。在AUTOSAR自适应平台上,建模进程在运行时实现为操作系统进程。关于执行管理如何启动和停止进程的详细信息,请参见第7.4节。
执行管理对所有可执行文件及其派生的建模进程一视同仁,与应用程序边界无关。
注意:在本版本文档中,通常假设进程是自包含的,即它们负责通过从代码内部调用操作系统接口的API来控制线程创建和调度。执行管理仅启动和终止进程,在进程运行时,执行管理仅通过提供状态管理机制(参见7.5)或支持确定性执行的API(参见7.6.3)与进程交互。
7.2.5 执行清单
执行清单与服务实例清单(执行管理不使用)一起在设计时创建,并与它所附加的可执行文件一起部署到机器上。
执行清单指定了可执行文件与部署相关的信息,并以标准化方式描述了建模进程属性(启动参数、资源组分配、调度优先级等)的机器特定配置。
执行清单与实际的可执行代码捆绑在一起,以支持将可执行代码部署到机器上。
每个可执行二进制文件的实例,即每个启动的进程,都可以单独配置,并且可以选择根据机器状态或功能组状态使用不同的配置集(参见第7.5节和[TPS_MANI_01012]、[TPS_MANI_01013]、[TPS_MANI_01014]、[TPS_MANI_01015]、[TPS_MANI_01059]、[TPS_MANI_01017]和[TPS_MANI_01041])。
为了执行必要的操作,执行管理对执行清单的内容提出了一些要求。
有关执行清单规范的更多信息,请参见[4]。
7.2.6 机器清单
机器清单也是在集成时为特定机器创建的,并在其内容发生变化时像执行清单一样部署。机器清单包含所有无法分配给特定可执行文件或其实例(建模进程)的配置信息,即尚未被执行清单或服务实例清单覆盖的信息。
机器清单的内容包括机器属性和功能(资源、安全、安保等)的配置,例如配置的机器状态和功能组状态、资源组、访问权限组、调度器配置、SOME/IP配置、内存分段。详细信息参见[4]。
7.2.7 清单格式
执行清单和机器清单可以从原始的标准化ARXML转换为平台特定格式(称为已处理清单),该格式在机器启动时可以有效读取。格式转换可以在集成时的离线进行,也可以在部署时进行,或者在机器上(由更新和配置管理)在安装时进行。
7.3 执行管理职责
执行管理负责进程执行管理的所有方面。进程是应用程序一部分的可执行文件的已加载实例。
执行管理作为AUTOSAR自适应平台启动阶段的一部分启动,并负责启动和终止进程。
执行管理根据机器清单和执行清单中的信息,决定何时以及可能按何种顺序启动或停止进程,即可执行文件的已部署实例。
执行管理确保所有可执行文件及可执行文件相关数据(如清单)的完整性和真实性得到检查。如果完整性或真实性检查失败,执行管理将执行第7.9节中定义的措施。
[SWS_EM_01030]{草案} 限制进程的进程创建权限 [执行管理应限制进程的权限,使其无法启动其他进程。]
[SWS_EM_01030] 的机制是实现特定的,但可以通过在进程创建时配置进程能力属性掩码来实现。
根据机器状态或任何其他功能组状态,已部署的可执行文件在AUTOSAR自适应平台启动期间或之后启动,但并非期望所有进程都立即开始主动工作,因为许多进程会向其他进程提供服务,因此等待并“监听”传入的服务请求。
执行管理基于声明的执行依赖关系 [SWS_EM_01050],在机器和/或功能组状态变化的上下文中推导出已部署可执行文件的启动/关闭顺序。依赖关系在执行清单中描述,参见 [TPS_MANI_01041]。
执行管理不负责进程的运行时调度,因为这是操作系统的责任 [SWS_OSI_01003]。然而,执行管理负责初始化/配置操作系统,使其能够基于执行管理从机器清单和执行清单中提取的信息,执行必要的运行时调度和资源管理。
执行管理不执行标准化的终止处理——因此,执行管理收到信号(例如 SIGTERM)的响应是实现定义的。
7.4 进程生命周期管理
7.4.1 执行状态
执行状态描述了进程的内部生命周期特征。换句话说,它们从正在执行的进程的角度描述了进程。进程可见的状态由 ara::exec::ExecutionState 枚举定义。
进程的执行状态被执行管理用来构建和维护第7.4.2节中描述的进程状态。来自进程的执行状态变更通知导致执行管理管理的进程状态变更。执行状态和进程状态是分开维护的,因此进程的执行状态与执行管理的进程状态之间没有显式依赖关系。这允许将来进程状态的发展而不影响进程内部的执行状态。
无论进程是通过隐式还是显式报告其执行状态来达到 kRunning 状态,执行管理都认为进程初始化完成。
进程需要使用 ara::exec::ExecutionClient::ReportExecutionState 接口报告 kRunning 状态(参见 [SWS_EM_01004])。它通常应在完成初始化之后、服务发现完成之前报告。如果进程仅在服务发现完成后才报告 kRunning,则由于执行依赖关系解析的延迟,非确定性延迟可能会影响其他进程。
[SWS_EM_01055] 启动进程终止 [执行管理应通过向进程发送 SIGTERM 信号来启动进程终止。]
请注意,从执行管理的角度来看,需求 [SWS_EM_01055] 仅要求启动终止所需的步骤。
根据 [SWS_EM_01055](例如在执行依赖关系处理期间)应被终止的进程可能已不再存活。但是,由于执行管理可以确定子进程的状态,因此不会尝试终止不再存在的进程。
执行管理可以在任何时候发送 SIGTERM,甚至在进程尚未报告 kRunning 状态、仍处于初始化进程状态时也是如此。
收到 SIGTERM 后,进程只需开始实际的终止。在终止状态期间,进程应保存持久数据并释放所有内部使用的资源。进程通过以退出状态 0 (EXIT_SUCCESS) 终止来表示终止状态完成。
执行管理不需要进程本身显式通知实际进程终止,因为这会引入竞争条件。相反,作为父进程的执行管理可以检测到子进程的终止,并采取适当的平台特定操作,例如处理依赖于已终止状态的执行依赖关系,从而确保在这些进程都运行时它们之间没有重叠。
[SWS_EM_01314]{草案} terminationBehavior 的默认值 [执行管理应将没有配置 terminationBehavior 的建模进程视为非自终止进程。此类建模进程应仅在执行管理请求时终止。]
[SWS_EM_01309]{草案} 进程的意外终止 [如果发生意外终止,执行管理应执行以下操作:
- 根据需要记录事件
- 将当前功能组状态设置为未定义功能组状态。
- 通过
ara::exec::StateClient::GetExecutionError接口报告配置的 executionError。]
请注意,[SWS_EM_01309] 也适用于意外自终止。
进程执行正确的执行状态报告是执行管理行为一致的一部分。
[SWS_EM_02243]{草案} 处理执行状态 Running [当进程报告执行状态 kRunning 且该进程不处于初始化进程状态时,执行管理应返回 kInvalidTransition。]
为了防止对执行管理的拒绝服务攻击,一种实现可以对接受执行状态报告进行速率限制,或者请求操作系统终止底层进程,但是此类反应尚未标准化。
执行管理区分两种类型的进程:上报进程和非上报进程。上报进程被认为是进程的正常形式,而非上报进程被认为是一种例外。
非上报进程可用于支持运行并非为 AUTOSAR 自适应平台设计的可执行文件。例如,如果可执行文件仅以二进制形式可用,如果无法修补其源代码,或者如果可执行文件仅在开发期间使用。
[SWS_EM_01402] 隐式运行进程状态 [对于非上报进程,在执行管理分配所需资源并创建运行时进程后,从启动到运行进程状态的转换应隐式应用。]
在安全相关系统中,系统设计者必须谨慎使用非上报进程功能。此类进程可能不会提供安全关键功能,也不会被平台健康管理监控,但它们仍可能影响其他安全相关进程,因此可能引入安全风险。为了将非上报进程与安全关键部分隔离,可以使用资源组(参见第7.7节)。
非上报进程尝试报告执行状态被视为执行管理的错误,参见 [SWS_EM_01403]。
7.4.2 进程状态
进程状态从执行管理的角度描述了进程的生命周期特征。换句话说,它们表示执行管理对执行状态(参见第7.4.1节)的内部跟踪。请注意,每个进程都是独立的,因此都有自己的进程状态。进程状态被执行管理用于解析执行依赖关系、管理超时等。
[SWS_EM_01401] 进程自我上报 [AUTOSAR 自适应平台实现应仅允许进程上报其自身的 ExecutionState。]
[SWS_EM_01002] 空闲进程状态 [空闲进程状态应为创建进程和分配资源之前的进程状态。]
[SWS_EM_01003] 启动进程状态 [当进程已创建且资源已分配时,应应用启动进程状态。]
[SWS_EM_01004] 上报进程的运行进程状态 [上报进程在向执行管理报告 kRunning 执行状态后,应应用运行进程状态。]
[SWS_EM_01404] 终止请求后的终止进程状态 [当执行管理向进程发送 SIGTERM 信号后,应应用终止进程状态。]
[SWS_EM_01405] (已废弃) 终止报告后的终止进程状态 [当上报进程决定自终止并通过报告 kTerminating 执行状态通知执行管理时,应应用终止进程状态。]
[SWS_EM_01006] 已终止进程状态 [进程终止且进程资源释放后,应应用已终止进程状态。]
对于 [SWS_EM_01006],执行管理观察所有进程的退出状态。该机制是实现相关的,但例如可以使用 POSIX waitpid() API。
从资源分配的角度来看,已终止进程状态类似于空闲进程状态——没有进程运行,也没有分配资源。但是从执行的角度来看,已终止进程状态与空闲状态不同,因为它告诉执行管理该进程已经执行、终止,并且可以根据需要按照 [SWS_EM_01066] 的规定重新启动。进程状态空闲和已终止之间的区别对于解析对自终止进程的执行依赖关系(参见第7.4.3.1节)是相关的。
7.4.3 启动和终止
7.4.3.1 执行依赖关系
执行管理可以基于声明的执行依赖关系,在状态管理框架内推导出进程启动和终止的顺序。这确保了在依赖应用程序使用它们提供的服务之前启动应用程序,同样,仅在不再需要它们提供的服务时才关闭应用程序。
执行依赖关系(参见 [TPS_MANI_01041] 和 [constr_1606])在执行清单中配置,该清单是在集成时基于应用程序开发人员提供的信息创建的。执行依赖关系定义了进程提供其功能所需的功能提供者。执行管理确保在定义依赖关系的进程启动之前,被依赖的进程处于执行依赖关系定义的状态。
用户级应用程序应使用通信管理的服务发现机制作为执行排序的主要机制,因为这在单机器内和跨机器边界都得到支持。因此,除非绝对必要,用户级应用程序不应依赖执行依赖关系。哪些进程正在运行取决于当前的功能组状态,包括机器状态,参见第7.5节。集成者应确保所有服务依赖关系都映射到状态管理配置,即确保所有依赖的进程在需要时都在运行。
在实际中,指定对某个进程的简单依赖关系可能不足以确保依赖的服务确实被提供。由于某些进程需要达到特定的执行状态(参见第7.4.1节)才能向其他进程提供服务,依赖关系信息还应引用作为依赖项指定的进程的进程状态。考虑到这一点,依赖关系信息可以表示为一个对:<进程>.<进程状态>。有关进程状态的更多详细信息,请参见第7.4.2节。
已识别以下依赖用例:
对运行进程状态的依赖:如果进程 B 对进程 A 有简单依赖,则在进程 B 的执行清单的依赖部分中指定进程 A 的运行进程状态。当进程 B 对进程 A 有运行执行依赖时,进程 B 将仅在进程 A 向 EM 报告运行状态后才启动。
对已终止进程状态的依赖:如果进程 D 依赖于自终止进程 C,则在进程 D 的执行清单的依赖部分中指定进程 C 的已终止进程状态。如果进程 D 对进程 C 有已终止执行依赖,则进程 D 将仅在进程 C 达到已终止状态后才启动。
如果在非自终止进程上指定了已终止执行依赖,则根据定义,它将超时,因为该进程直到下一次功能组转换才会终止。
考虑三个进程:
- Storage,一个没有任何依赖关系的服务进程;
- StorageConsistencyChecker,一个自终止进程,它要求 Storage 处于运行进程状态;
- ConfigReader,一个服务进程,它要求 StorageConsistencyChecker 已达到已终止进程状态;
对于启动,这意味着执行管理应启动 Storage 并等待它报告 kRunning,然后执行管理应启动 StorageConsistencyChecker 并等待它终止,然后才启动 ConfigReader。对于终止,执行依赖关系表明执行管理可以同时终止 Storage 和 ConfigReader,因为 StorageConsistencyChecker 已经终止,并且 ConfigReader 对 Storage 没有直接依赖。如果 ConfigReader 必须在 Storage 之前终止,则可以通过在 ConfigReader 和 Storage 之间添加直接执行依赖关系来实现。
所需的依赖关系信息由应用程序开发人员提供。它在集成时适用于特定的机器环境,并在执行清单中提供。
执行管理解析该信息,并使用它来构建启动序列,以确保在启动依赖进程之前,所需的前置进程已达到特定的进程状态 [SWS_EM_01050]。
[SWS_EM_01001] 执行依赖错误 [如果执行管理需要启动依赖于另一个进程 B 的进程 A,并且进程 B 与进程 A 不属于同一功能组状态,则执行管理应将其视为错误,并无法启动进程 A。]
示例 7.4
假设进程 “A” 依赖于进程 “B” 的运行进程状态。在机器状态转换时,进程 “A” 应被启动,因为它引用了新的机器状态。然而,进程 “B” 没有引用该机器状态,因此它没有被启动。由于两个进程之间的执行依赖关系,进程 “A” 将永远无法在新机器状态下启动运行,因为它会永远等待进程 “B”。这被认为是一个配置错误,并且也应导致运行时错误。
请注意,需求 [SWS_EM_01001] 有效地禁止了任何跨出单个功能组状态(或机器状态)定义的执行依赖关系,另请参见 [constr_1689]。这是有意为之,因为这种依赖关系会在功能组之间引入隐藏依赖关系,并且它们对状态管理不可见。如果需要表达功能组之间的依赖关系(例如,地图软件可能依赖于 GPS 软件),则应在状态管理内部完成。更多信息参见 [11]。
与上报进程不同,非上报进程在启动后立即处于运行进程状态。无论进程是否已完成其初始化阶段并准备好提供服务。这意味着运行执行依赖关系会立即得到满足,因此如果不采取进一步措施,对于非上报进程指定时不会达到原始语义。
这个限制可以通过引入一个伴随进程来克服,该伴随进程作为非上报进程的代表。伴随进程等待非上报进程提供的服务的可用性,并向执行管理报告 kRunning。实际需要非上报进程服务的进程可以配置为依赖于伴随进程。请注意,已终止执行依赖关系不受影响,因为当非上报进程终止时,执行管理会收到操作系统的通知。详细信息请参见图7.5。
- 非上报进程(和自终止进程)A 引用 FG1: Running。此进程首先启动(因为它没有配置任何执行依赖关系),并根据 [SWS_EM_01402] 自动进入运行进程状态。
- 伴随进程 B 在非上报进程 A 之后启动(请注意,A 和 B 也是标准 AUTOSAR 进程)进入运行状态。进程 B 可以使用项目特定的方法来评估进程 A 是否完全正常运行,并通过报告(或不报告)kRunning 状态将此信号通知给执行管理。
- 进程 C 在(且仅在)进程 B 进入运行进程状态(即报告 kRunning)时启动。请注意,此执行依赖关系将独立于进程 C 的上报/非上报配置而工作。
- 进程 D 对自终止进程(和非上报进程)A 配置了已终止执行依赖关系。如前所述,这开箱即用(此处无需特殊操作)。
请注意,此方法还可用于向平台健康管理传达健康状态。
7.4.3.2 参数
执行管理为进程提供参数传递,其中包含一个或多个 StateDependentStartupConfig,角色为 Process.stateDependentStartupConfig。这允许使用不同的参数启动不同的进程。
[SWS_EM_01012] 进程参数传递 [在启动进程时,执行管理应基于 [SWS_EM_01072] 和 [SWS_EM_01078] 将 StateDependentStartupConfig 引用的 StartupConfig 聚合的 ProcessArgument 传递给进程。]
请注意,[SWS_EM_01012] 有意未指定用于启动进程的 OS 机制,例如基于 exec 族的 POSIX 接口,因为这最终是实现特定的属性。
由执行管理传递的第一个参数是可执行文件的名称。
[SWS_EM_01072] 进程参数零 [参数 0 应设置为可执行文件的名称。]
执行管理支持以与 shell 将命令行参数传递给 POSIX 进程相同的方式将参数传递给进程。执行管理将每个 ProcessArgument.argument 分配给 argv[] 数组的一个元素,从元素索引 1 开始,并将其传递给进程 main() 函数。ProcessArgument 顺序用于保留(选项,参数)对的语义,例如 “-b value”,其中 “-b” 参数必须位于 “value” 参数之前。此方法支持 POSIX 环境中通常使用的短格式和长格式参数传递约定。
[SWS_EM_01073] (已废弃) 简单参数 [对于每个位置 n 且 StartupOption.optionKind = commandLineSimpleForm 的聚合 StartupOption,第 n 个参数应为 StartupOption.optionArgument。]
[已废弃] 执行管理支持短格式参数,通常是单个字符。所有短格式参数以单破折号 (-) 开头,该破折号不包含在 StartupOption.optionName 中。
[SWS_EM_01074] (已废弃) 带选项值的短格式参数 [对于每个位置 n 且 StartupOption.optionKind = commandLineShortForm 且 StartupOption.optionArgument 的多重性 = 1 的聚合 StartupOption,第 n 个参数应为 ‘- + StartupOption.optionName + ’ ’ + StartupOption.optionArgument]
[已废弃] 请注意,需求 [SWS_EM_01074] 包括对强制性空格的指定;这由需求文本中的 ’ ’ 表示。
[SWS_EM_01075] (已废弃) 不带选项值的短格式参数 [对于每个位置 n 且 StartupOption.optionKind = commandLineShortForm 且 StartupOption.optionArgument 的多重性 = 0 的聚合 StartupOption,第 n 个参数应为 ‘- + StartupOption.optionName]
[已废弃] 执行管理支持长格式参数,通常对用户来说比短格式参数更有意义。为了区分长格式参数和短格式参数,前者以双破折号 (–) 开头,该破折号不包含在 StartupOption.optionName 中。
[SWS_EM_01076] (已废弃) 带选项值的长格式参数 [对于每个位置 n 且 StartupOption.optionKind = commandLineLongForm 且 StartupOption.optionArgument 的多重性 = 1 的聚合 StartupOption,第 n 个参数应为 ‘– + StartupOption.optionName + ’ ’ + StartupOption.optionArgument]
[SWS_EM_01077] (已废弃) 不带选项值的长格式参数 [对于每个位置 n 且 StartupOption.optionKind = commandLineLongForm 且 StartupOption.optionArgument 的多重性 = 0 的聚合 StartupOption,第 n 个参数应为 ‘– + StartupOption.optionName]
[SWS_EM_01078]{草案} 进程参数字符串 [ProcessArgument.argument 应按顺序传递给进程,第一个 ProcessArgument.argument 从进程参数 1 开始。]
7.4.3.3 环境变量
执行管理为进程初始化环境变量。进程特定的环境变量在其执行清单中配置。机器特定的环境变量在机器清单中配置。在运行时,可通过 POSIX getenv() 命令访问环境变量。
[SWS_EM_02246] 进程特定环境变量 [执行管理应基于 Process.stateDependentStartupConfig.startupConfig.environmentVariable 的配置准备环境变量,并在进程启动时传递它们。]
[SWS_EM_02247] 机器特定环境变量 [执行管理应基于 Machine.environmentVariable 的配置准备环境变量,并在进程启动时传递它们。]
请注意,AUTOSAR 元模型(参见 [4])对环境变量定义使用 TagWithOptionalValue([TPS_MANI_01208] 和 [TPS_MANI_01209])。如其中所述,可以省略值(TagWithOptionalValue.value)作为指定空值环境变量的一种方式。
[SWS_EM_02249] 环境变量定义中缺少值 [每当执行管理发现环境变量定义缺少 TagWithOptionalValue.value 时,它应使用空字符串作为此环境变量的值。]
[SWS_EM_02248] 环境变量优先级 [每当同一环境变量在执行清单和机器清单中都配置时,执行管理应使用执行清单中的环境变量值。]
7.4.4 机器启动序列
执行管理是 AUTOSAR 自适应平台的第一个进程。准备就绪后,执行管理启动机器状态从 Off 状态(EM 启动前的默认状态)到启动状态的转换([SWS_EM_01023]、[SWS_EM_02250])。在转换期间,执行管理请求启动存在于启动机器状态中的进程。
在满足必要的状态转换条件(参见第7.5.5节和第7.5.2.1节)后,执行管理向状态管理报告机器状态启动转换确认([SWS_EM_02241])。此时,执行管理将功能组状态管理(即发起状态更改请求)的责任移交给状态管理。
在机器上(可以是任何资源组,即物理环境、虚拟机管理程序上的虚拟化环境或操作系统级虚拟化(容器)),执行管理不一定是启动的第一个进程;系统可能需要其他进程,例如操作系统 init 进程或操作系统微内核用户级进程,如驱动程序、文件系统等。所有这些进程可能在 AUTOSAR 自适应平台的上下文之外启动和管理。
请注意,一个应用程序由一个或多个可执行文件组成。因此,要启动一个应用程序,执行管理会启动作为每个可执行文件实例的进程。
[SWS_EM_01000] 启动顺序 [平台级进程的启动顺序应由执行管理基于机器清单和执行清单信息确定。]
请参见第7.2.5节。
图7.6显示了整个启动序列。
7.5 状态管理
7.5.1 概述
状态管理功能集群定义了 AUTOSAR 自适应平台的操作状态,而执行管理执行不同状态之间的转换。
执行清单允许定义建模进程必须在哪些状态下运行(参见 [4])。如前所述,建模进程是可执行文件的一个实例,是应用程序的一部分。状态管理机制完全控制要执行的应用程序集,并确保仅在真正需要时才执行进程(从而分配资源)。
与执行管理相关的有四种不同状态:
- 执行状态 - 执行状态表征每个已启动进程的内部生命周期,参见第7.4.1节
- 进程状态 - 进程状态由执行管理内部状态机管理。详细信息参见第7.4.2节。
- 机器状态 - 参见第7.5.2节
- 功能组状态 - 参见第7.5.3节
这些状态之间交互的示例将在第7.5.4节中展示。
7.5.2 机器状态
执行管理要求每个机器至少配置一个功能组。此功能组应命名为 “MachineFG”。
功能组 “MachineFG” 有几个强制状态(参见 [SWS_EM_02250]),这些状态也应为每个机器配置。可以基于机器特定定义额外的机器状态,因此这些状态未标准化。
功能组状态(包括 “MachineFG” 的机器状态)定义了当前正在运行的进程集。每个应用程序可以在其执行清单中声明其进程应在哪些功能组状态下运行。每个所需机器状态的 ModeDeclaration 必须在机器清单中定义 [constr_1687] [TPS_MANI_03194]。
机器状态(以及其他功能组状态)由状态管理请求。活动状态集受整车范围事件和模式的显著影响。有关状态更改管理的详细信息,请参见第7.5.5节。
[SWS_EM_01032]{草案} 机器状态配置 [执行管理应从机器清单获取功能组 “MachineFG” 的配置,并设置机器状态管理。]
从初始状态启动到状态管理 (SM) 请求初始运行状态 StateXYZ 的启动序列如图7.8所示。
图7.9示例如下:收到状态更改请求后,执行管理终止正在运行的进程,然后启动在新状态中活动的进程,然后向状态管理确认状态更改。
7.5.2.1 启动
[SWS_EM_02250]{草案} 机器状态启动 [如果功能组 “MachineFG” 未配置启动状态,执行管理应停止 AUTOSAR 自适应平台启动。]
停止后有多种可能的策略;暂停(例如在无限循环中)、中止(例如通过看门狗重置 ECU)等。选择是实现特定的。
[SWS_EM_01023]{草案} 机器状态启动转换的自发起 [执行管理应在执行管理启动后尽快自发起到启动机器状态的转换。]
请注意,对于机器状态转换,第7.5.5节的要求适用。
[SWS_EM_02241]{草案} 机器状态启动完成 [在完成初始(自发起)机器状态到启动状态的转换后,执行管理应通知状态管理已达到机器状态的启动状态。]
达到启动状态后(如 [SWS_EM_02241] 所述),执行管理不发起任何进一步的功能组状态更改(包括机器状态)。相反,此类更改由状态管理请求,然后由执行管理执行。
执行管理将受其他软件实体控制,不应自行执行任何功能组状态更改([SWS_EM_01023] 是一个例外)。这对系统配置产生了一些期望。该规范期望状态管理将在每个机器状态(包括启动、关闭和重启)中运行。需要上述期望是为了确保始终有一个软件实体可以引入机器当前状态的更改。如果(例如)系统集成商未配置状态管理在启动机器状态下启动,则机器将永远无法转换到任何其他状态,并将永远卡在该状态。这也适用于任何其他未配置状态管理的机器状态。
7.5.2.2 关闭/重启
执行管理不执行操作系统的关闭/重启。相反,它要求至少一个进程提供一种机制来关闭操作系统。此进程应配置为在相关机器状态下运行。参见 [4] [constr_1618] 和 [constr_1619]。
[constr_1687] 强制要求指定关闭/重启机器状态。执行管理可以检查是否为功能组 “MachineFG” 配置了该状态,并根据需要采取实现特定的操作(例如记录),但平台启动可以继续进行。
将当前机器状态更改为关闭或重启的请求发送给执行管理,其处理方式与任何其他功能组状态更改请求相同。从执行管理的角度来看,所有功能组都是独立的,因此对它们的更改可以在没有任何副作用的情况下应用。
然而,从状态管理的角度来看,由于存在不同功能组之间依赖关系的知识,这可能不成立。AUTOSAR 假设状态管理将在有效时请求 “MachineFG” 关闭或重启;有关如何编排机器关闭的建议,请参见 [11]。
请注意,系统集成者有责任仔细考虑何时应请求系统关闭/重启,因为所有仍在运行的进程将不会被执行管理终止,这意味着它们将无法持久化其数据。
如第7.5.2.1节所述,AUTOSAR 假设状态管理将配置为在关闭和重启状态下运行。状态转换不是简单的系统更改,并且可能因多种原因失败——在这种情况下,状态管理应保持活动状态,以便您可以报告错误并等待进一步指令。请注意,此状态的目的是以干净的方式关闭或重启机器(包括状态管理)。不幸的是,这意味着在某个时刻,状态管理将不再可用于报告错误,后续错误应通过实现特定的机制来处理。
7.5.3 功能组状态
如果机器上安装了一组功能连贯的应用程序,那么能够一起控制它们将很有用。正是出于这个原因,AUTOSAR 自适应平台引入了功能组的概念。
每个功能组都有自己的进程集和称为功能组状态的状态集。每个功能组状态定义了当状态管理请求执行管理激活功能组状态时,应启动哪些进程。请注意,功能组的最小大小是一个进程,最大大小受实现限制。
功能组机制非常灵活,旨在作为用于启动和停止应用程序进程的工具。系统集成商可以将进程分配给功能组状态,然后由状态管理请求。有关状态更改管理的详细信息,请参见第7.5.5节。
通常,机器状态(参见第7.5.2节)用于控制机器生命周期(启动/关闭/重启)和平台级应用程序的进程,而其他功能组状态则分别控制属于功能连贯的用户级应用程序组的进程。请注意,这并不意味着所有平台级应用程序的进程都必须由机器状态控制。
图7.10显示了一个状态更改序列示例,其中多个进程引用了机器状态和两个额外功能组 FG1 和 FG2 的功能组状态。为简单起见,每个进程仅显示了三个静态进程状态:空闲、运行和已终止。
- 进程 A 引用机器状态启动。它是一个自终止进程,即执行一次后终止。
- 进程 B 引用机器状态启动和运行。它依赖于进程 A 的终止,即已配置执行依赖关系,如第7.4.3.1节所述。
- 进程 C 仅引用机器状态运行。当状态管理请求机器状态诊断时,它会终止。
- 进程 D 和 E 仅引用功能组状态 FG1: Running,并且它们之间没有配置执行依赖关系。执行管理将以任意顺序(例如尽可能并行)启动和终止它们。
- 进程 F 引用 FG2:Running 和 FG2:Fallback。它为两个状态分配了不同的启动配置,因此它在状态转换时终止,并使用不同的启动配置重新启动。
系统设计和集成应确保机器上始终有足够的资源可用,即同时引用活动状态的所有进程的额外资源消耗应予以考虑。
[SWS_EM_01107]{草案} 功能组配置 [执行管理应从机器清单获取功能组的配置,以设置功能组特定的状态管理。]
正确的系统配置要求每个进程在其执行清单中引用同一功能组的一个或多个功能组状态(可以是机器状态)。
[SWS_EM_01013]{草案} 功能组状态 [执行管理应支持根据当前功能组状态和执行清单中提供的信息执行特定的建模进程。]
每个建模进程被分配到一个或多个启动配置 (StartupConfig),每个配置可以定义一个或多个功能组状态(包括机器状态)中的启动行为。详细信息参见 [4]。通过解析执行清单中的此信息,执行管理可以确定如果进入特定功能组状态,需要启动哪些建模进程,以及哪些启动参数有效。
[SWS_EM_01033]{草案} 进程启动配置 [为了使建模进程能够在多个功能组状态下启动,执行管理应能够基于执行清单中提供的信息,在每个功能组状态更改时配置建模进程的启动。]
[SWS_EM_01109]{草案} 配置错误的进程 - 未分配给功能组 [在系统配置错误的情况下,执行管理不应启动至少未引用一个状态的进程。]
[SWS_EM_02254]{草案} 配置错误的进程 - 分配给多个功能组 [在系统配置错误的情况下,执行管理不应启动引用来自多个功能组的状态的进程。]
请注意,AUTOSAR 不支持将单个进程分配给多个功能组的可能性,参见 [4] ([constr_1688])。
[SWS_EM_01110]{草案} Off 状态 [每个功能组(包括功能组 “MachineFG”)都有一个 Off 状态,如果没有请求其他状态,执行管理应将其用作默认功能组状态。]
请注意,[SWS_EM_01110] 和 [SWS_EM_01023] 共同定义了上电后的第一个功能组状态转换。当执行管理启动时,它执行从 “off” 状态(默认状态)到 “startup” 状态的机器状态转换。
“off” 状态是强制性的 [TPS_MANI_03195],并且不得映射建模进程 [constr_3424]。
进程在其执行清单中引用它们希望执行的状态。状态可以是任何功能组状态,包括机器状态。详细信息参见 [4],特别是 “State-dependent Startup Configuration” 章节和 “Function Groups” 章节。
图7.9所示的任意状态更改序列适用于任何功能组的状态更改——只需将 “MachineFG” 替换为功能组的名称。收到状态更改请求后,执行管理终止不再需要的进程,然后启动在新功能组状态中活动的进程,然后向状态管理确认状态更改。详细信息参见第7.5.5节。
7.5.4 状态交互
图7.11显示了一个简化示例,说明在状态管理功能集群请求了不同的功能组状态后,不同类型状态之间的交互。可以看到功能组的状态转换以及一个进程的进程和执行状态,该进程引用了此功能组的一个状态,忽略了可能涉及多个进程时的延迟和依赖关系。
7.5.5 状态转换
状态管理可以使用第8.2.7节中描述的 API 请求更改一个或多个功能组状态(包括机器状态)。StateClient::SetState 允许状态管理并行请求多个功能组状态更改。如果需要更改机器状态,传递的功能组名称应为:“MachineFG”。
在我们详细说明状态转换的内部工作原理之前,让我们考虑图7.12所示的示例配置。正如我们所见,跨越功能组甚至单个功能组状态的执行依赖关系是被禁止的。从进程 B(在功能组 FG_B 内)到进程 A(在功能组 FG_A 内)的依赖关系是被禁止的,因为它会在功能组之间引入对状态管理不可见的隐藏依赖关系。如果系统配置需要这种依赖关系,请参阅 [11] 了解如何配置它们。跨越单个功能组状态定义的依赖关系是被禁止的,因为它们会导致启动未配置为在给定状态下运行的进程。有关执行依赖关系的更多信息,请参见第7.4.3.1节([SWS_EM_01001] 和 [constr_1689])。
请注意,进程 B 在功能组状态 ABC 和功能组状态 XYZ 中具有不同的执行依赖关系。此配置要求存在两个不同的启动配置 (StateDependentStartupConfig),这反过来将强制进程 B 在状态管理请求将功能组状态从 ABC 更改为 XYZ 时重新启动。这由 [SWS_EM_02251] 强制执行。
从以上可以得出结论,每个功能组都是一个独立的实体,一个功能组的状态转换不会对另一个功能组产生副作用。请注意,从执行管理的角度来看这是正确的,但从状态管理的角度来看可能不同(如果需要更多信息,请参阅 [11])。
在以下需求中,术语“进程引用一个状态”意味着建模进程在其执行清单中有一个 StateDependentStartupConfig 的聚合,角色为 Process.stateDependentStartupConfig,其中包含对 ModeDeclaration 的 instanceRef,角色为 StateDependentStartupConfig.functionGroupState,该 ModeDeclaration 属于该状态。
CurrentState 是当前(当前活动的)功能组状态(如果功能组名称为 “MachineFg”,则是当前机器状态),为其请求了状态转换。简而言之,这是功能组状态或机器状态。
RequestedState 是状态转换成功完成后将成为 CurrentState 的状态。
换句话说,CurrentState 是转换的起点,是应在功能组内当前运行的进程列表(请注意自终止进程的存在)。RequestedState 是状态转换的目标点,是状态转换成功完成后将在功能组内运行的进程列表(请注意自终止进程的存在)。
StartupConfig 是 StateDependentStartupConfig,它针对给定进程聚合在角色 Process.stateDependentStartupConfig 中。
状态转换是一个复杂的过程,但它由三个简单的逻辑步骤组成:
- 终止所有当前正在运行但在 RequestedState 中不需要的进程
- 重新启动所有当前正在运行且在 CurrentState 和 RequestedState 之间 StartupConfig 不同的进程
- 启动所有当前未运行但在 RequestedState 中需要的进程
请参阅第7.4.1节和第7.4.2节,了解有关执行管理如何处理进程终止和启动的更详细信息(重新启动是终止和启动的序列)。
[SWS_EM_01060]{草案} 状态转换 - 终止行为 [在状态转换时,执行管理应终止所有在其执行清单中引用 CurrentState 但不引用 RequestedState 且进程状态不同于 [空闲或已终止] 的进程。]
[SWS_EM_02311]{草案} 进程终止超时反应的顺序 [执行管理应在向状态管理报告之前执行终止反应 [SWS_EM_02255]。]
[SWS_EM_02312]{草案} 进程启动超时反应的顺序 [执行管理应在向状态管理报告之前执行终止反应 [SWS_EM_02310]。]
当启动新进程时,执行管理有义务执行依赖关系解析。这样做时,它可能会遇到一种配置,其中进程 B 依赖于进程 A,但进程 A 需要在状态更改期间重新启动。另一个示例是配置,其中进程 D 依赖于自终止进程 C 处于已终止进程状态。进程 C 必须在请求的功能组状态下启动和终止,以满足 D 的执行依赖关系。有关详细信息,请参见图7.13。
[SWS_EM_02245]{草案} 状态更改期间的依赖关系解析 [执行管理应确保针对为 RequestedState 配置的进程执行执行依赖关系解析。]
请注意,[SWS_EM_02245] 并未给状态转换带来新功能。它只是确保 [SWS_EM_02251] 和 [SWS_EM_01066] 在进程 A 上执行,然后才在进程 B 上执行 [SWS_EM_01066]。如果不确保此顺序,则无法满足 [SWS_EM_02245],因为进程 A 将是为 CurrentState 而不是为 RequestedState 配置的进程。
本章中对功能组状态转换的描述可能给人的印象是,需要先停止所有在 RequestedState 中不需要的进程,然后才能启动任何需要的进程。请注意,事实并非如此。本章的分步方法是为了在描述功能组状态转换时尽可能引入清晰性。对于特定实现,允许实现者尽可能并行化状态转换所需的步骤。
执行管理在发生以下情况时认为状态转换已成功执行:
- 依赖关系解析 ([SWS_EM_02245]) 已识别要启动/停止的进程
- 所有预期终止的进程均已终止 ([SWS_EM_01060])
- 所有已启动 ([SWS_EM_01066]) 或重新启动 ([SWS_EM_02251]) 的上报进程均已报告 kRunning。
[SWS_EM_01067]{草案} 完成状态转换时的操作 [成功完成状态转换后,执行管理应将 Current State 设置为 RequestedState,并向状态管理报告成功。]
[SWS_EM_02313]{草案} 在功能组状态转换期间启动进程的意外终止 [如果在进程启动期间发生意外终止 ([SWS_EM_01066]),执行管理应执行以下操作:
- 停止功能组状态转换,以便状态管理决定如何继续。
- 根据需要记录事件
- 将当前功能组状态设置为未定义功能组状态。
- 在
ara::exec::StateClient::SetState接口中报告 kFailedUnexpectedTerminationOnEnter,以指示无法满足状态更改请求。 - 通过
ara::exec::StateClient::GetExecutionError接口报告配置的 executionError。]
[SWS_EM_02314]{草案} 在功能组状态转换期间终止进程的意外终止 [如果在进程终止期间发生意外终止 ([SWS_EM_01060], [SWS_EM_02251]),执行管理应执行以下操作:
- 停止功能组状态转换,以便状态管理决定如何继续。
- 根据需要记录事件
- 将当前功能组状态设置为未定义功能组状态。
- 在
ara::exec::StateClient::SetState接口中报告 kFailedUnexpectedTerminationOnExit,以指示无法满足状态更改请求。 - 通过
ara::exec::StateClient::GetExecutionError接口报告配置的 executionError。]
[SWS_EM_02297]{草案} StateClient 使用限制 [当 Process.functionClusterAffiliation 配置为 STATE_MANAGEMENT 以外的任何值时,StateClient API 在被进程调用时应返回 kCommunicationError。]
如果不加以保护,StateClient 可能被用来破坏机器的稳定性,详见第8.2.7节。
7.6 确定性执行
7.6.1 确定性
在实时系统中,确定性执行通常意味着,给定一组输入数据的计算总是在有界时间内产生一致的输出,即行为是可重现的。
在执行管理的上下文中,术语“计算”可以适用于线程、进程或一组进程的执行。计算可以是事件驱动的或周期性的,即时间驱动的。
同样值得注意的是,确定性必须与其他非功能性质量(如可靠性或可用性)区分开来,它们都以不同的方式处理故障的统计风险。确定性不提供此类数字,它仅定义没有错误时的行为。
确定性有多个要素,我们区分如下:
- 时间确定性:计算结果总是在给定截止时间(某个时间点)之前产生。
- 数据确定性:给定相同的输入和内部状态,计算总是产生相同的输出。
- 完全确定性:上述时间确定性和数据确定性的组合。
特别是,确定性行为对于安全关键系统很重要,这些系统可能根本不允许偏离指定行为。是否需要时间确定性,或者还需要数据确定性来提供所需的功能,取决于系统和安全目标。
需要这种确定性的 AUTOSAR 自适应平台的预期用例包括:
- 软件锁步:为了在高计算性能需求下执行 ASIL C/D 应用程序,需要特定的措施,例如软件锁步,这是由于高性能微处理器的高瞬态硬件错误率。软件锁步是一种技术,其中计算通过两个不同的执行路径冗余完成,并比较结果。为了使冗余计算具有可比性,软件锁步需要完全确定的计算。详细信息参见7.6.2。
- 已验证软件的重用:确定性子系统在不同平台上表现出相同的行为,这些平台满足子系统的性能和资源需求,而与每个环境中其他差异(例如不相关应用程序的存在)无关。示例包括不同的开发和仿真平台。由于可重现的功能行为,子系统的大量测试、配置和校准结果在部署子系统的每个环境中都是有效的,无需重复。
7.6.1.1 时间确定性
每次开始计算时,其结果保证在指定截止时间之前可用。为了实现这一点,应为执行计算的软件实体分配足够且有保证的计算资源(处理器时间、内存、服务响应时间等)。有关资源的更多信息,请参见第7.7章。
非确定性的“尽力而为”进程可以请求保证的最小资源以实现基本功能,并且还可以指定用于监控目的的最大资源。但是,如果要求时间确定性,则资源必须在任何时候都有保证,即最小和最大资源是相同的。
如果违反了确定性执行的假设,例如由于错过截止时间,则必须将其视为错误,并且必须启动恢复操作。在非确定性“尽力而为”子系统中,有时可以容忍和缓解此类截止时间违规或偏离正常行为的其他情况,而无需专门的错误管理。
完全确定性行为还需要数据确定性,但在许多情况下,时间确定性就足够了。
7.6.1.2 数据确定性
对于数据确定性,每次开始计算时,其结果仅取决于输入数据。对于特定的输入数据序列,假设相同的初始内部状态,结果必须始终完全相同。
在安全上下文中验证数据确定性的一种常见方法是使用锁步机制,其中执行通过两个不同的路径同时进行,并比较结果以验证一致性。硬件锁步意味着硬件具有特定的设备来使这种双重/多重执行透明。软件锁步是另一种技术,它允许提供类似的属性,而无需使用专用硬件。
根据安全级别以及所采用的安全概念,软件锁步可能涉及多次执行相同的软件(并行或顺序),但也可能涉及运行同一算法的多个单独实现。
7.6.1.3 完全确定性
对于完全确定性,每次开始计算时,其结果在指定截止时间之前可用,并且仅取决于输入数据,即必须同时保证时间确定性和数据确定性。
目前,支持单个进程的完全确定性行为。一台机器上的一组建模进程的确定性在文档 [12] 中概述。跨多台机器的确定性需要对通信管理进行扩展,这些扩展尚未指定。
非确定性行为可能由不同的原因引起;例如计算资源不足,或对数据的非协调访问,可能由多个线程在多个处理器内核上运行。线程访问此类数据的顺序将影响结果,这使其变得非确定性(“竞争条件”)。
完全确定的计算必须以这样一种方式进行设计、实现和集成,即它独立于由其他功能和计算引起的处理器负载、偶发的无关事件、竞争条件、偏差的随机数等,即对于相同的输入和初始条件,它总是在给定时间内产生相同的结果。
7.6.2 确定性客户端
如第7.6.1节所述,未来的系统需要结合高计算性能和高 ASIL 安全目标。在本章中,我们指定了支持确定性多线程执行以支持高性能软件锁步解决方案的机制。以下是一些额外的原理:
高度自动化驾驶 (HAD) 系统的安全目标可高达 ASIL D。高性能计算 (HPC) 需求只能由非汽车级(例如消费电子 (CE))微处理器满足,这些微处理器与汽车级微控制器相比具有较高的瞬态硬件错误率。很可能没有这样的微处理器可用于 ASIL 高于 B 级别,至少对于设计相关的部分而言。为了应对高错误率,ASIL C/D HAD 应用程序需要特定的措施,特别是软件锁步,其中执行通过两个不同的路径冗余完成,并比较结果以检测错误。为了使这些冗余计算具有可比性,软件锁步需要如第7.6.1.3节所定义的完全确定性计算。为了满足 HPC 需求,必须支持高度可预测和可靠的多线程处理。
两个冗余进程在内部周期中运行,每个周期通过通信管理的常规接口获得相同的输入数据,并且在没有错误的情况下产生相同的结果,这是由于完全确定性执行。
执行管理提供 DeterministicClient API,以支持控制进程内部周期、确定性工作池、激活时间戳和随机数。在软件锁步的情况下,DeterministicClient 与可选的软件锁步框架交互,以确保冗余执行的进程行为相同。DeterministicClient 与通信管理交互,以使数据处理与周期激活同步。
对于每个执行周期,软件锁步框架与通信管理合作同步输入数据,确保冗余执行进程的随机数和激活时间戳相同,同步触发执行,并比较输出以检测其中一个冗余进程中的故障(例如由于辐射导致的瞬态处理器内核或内存错误)。此基础架构层可以跨越多个硬件实例,并且是特定于实现的。
软件锁步框架的细节不在自适应平台规范的范围内。
AUTOSAR 自适应平台需要提供一些库函数来支持具有足够隔离度的冗余确定性执行。库函数 (DeterministicClient) 在用户进程的上下文中运行。图7.14考虑了如何在一个冗余执行进程中使用 DeterministicClient。
周期性进程行为由等待点 API 控制。API 返回一个代码来控制进程模式(注册服务/服务发现/初始化/运行/终止)。执行由 DeterministicClient 触发,取决于定义的周期或接收到的事件。在一个进程内,所有输入数据在开始执行时通过 ara::com(仅基于轮询的访问)可用,并且在一个执行周期内保持稳定。详细信息参见7.6.3.1。
工作负载可以部署到工作池 API,该 API 允许确定性执行一组容器元素(例如数据集),这些元素由同一个可运行对象(即应用程序函数)并行处理。可运行对象在运行时不允许交换任何信息,即它不访问可能被可运行对象其他实例更改的数据,以避免竞争条件。可运行对象实例可以在物理上并行或以任意顺序顺序运行。详细信息参见7.6.3.2。
其他 DeterministicClient API 提供随机数和激活时间戳。常见的 HAD 算法使用需要随机数的粒子滤波器。如果从工作池内部使用,随机数被分配给特定的容器元素以允许确定性冗余执行。激活时间戳在进程到达其下一个等待点之前不会改变。对于确定性冗余执行,随机数种子和时间戳需要同步。详细信息参见7.6.3.3和7.6.3.4。
在执行周期结束时,进程返回到等待点,等待下一次激活。
DeterministicClient 的 API 是标准化的,并提供了应用程序部署到实际硬件上的抽象。该实现是供应商特定的,并且需要在集成时为每个使用它的进程单独配置。
DeterministicClient 类仅对进程本地。因此,目前对此 API 没有预见到安全顾虑。
DeterministicClient 的不同变体可能在软件锁步环境中工作或独立工作,以支持周期性执行和确定性工作池。
7.6.3 周期性确定性执行
本节描述了图7.14中显示的 API,以及进程如何使用它们来确定性执行,以便进程可以透明地集成到软件锁步环境中。
7.6.3.1 周期性执行的控制
执行管理提供了一个 API 来触发和控制进程内主线程代码的循环执行。
[SWS_EM_01301] 周期性执行 [执行管理应提供一个阻塞等待点 API ara::exec::DeterministicClient::WaitForActivation。]
在进程由执行管理启动后,它报告 ara::exec::ExecutionState kRunning(参见7.4.1)并调用 ara::exec::DeterministicClient::WaitForActivation。
当 ara::exec::DeterministicClient::WaitForActivation 返回时,进程执行一个周期,然后再次调用 API 等待下一次激活。
返回值控制进程的内部生命周期(例如初始化、运行、终止),参见图7.14。返回码用于在冗余执行的情况下同步两个进程的行为。
[SWS_EM_01302] 周期性执行控制 [ara::exec::DeterministicClient::WaitForActivation 应返回一个代码来控制调用进程的执行模式。可能的代码有 kRegisterServices、kServiceDiscovery、kInit、kRun 和 kTerminate。]
从 ara::exec::DeterministicClient::WaitForActivation 返回的 ara::exec::ActivationReturnType 决定每个周期采取的操作:
- kRegisterServices - 进程注册其通信服务,即它通过通信管理提供的服务。这应该是执行服务注册的唯一场合。在此步骤中不应执行其他功能,以限制资源消耗和运行时间,因此无需分配专用预算。
- kServiceDiscovery - 进程执行通信服务发现。这应该是执行服务发现的唯一场合,除非以后需要替换服务(参见 ([SWS_EM_01304]))。在此步骤中不应执行其他功能,以限制资源消耗和运行时间,因此无需分配专用预算。
- kInit - 进程初始化其内部数据结构。工作池(参见7.6.3.2)可以顺序访问一次或多次。需要为 “Init” 周期分配预算(参见7.6.3.5)。
- kRun - 进程执行其正常周期性执行的一个周期。这可以无限重复。工作池(参见7.6.3.2)可以在一个周期内顺序访问一次或多次。需要分配预算(参见7.6.3.5)。
- kTerminate - 进程准备终止。实际终止根据 [SWS_EM_01404] 执行,参见第7.4.2节。
[SWS_EM_01303] 周期性执行控制序列 [ara::exec::DeterministicClient::WaitForActivation 的返回码应遵循以下顺序:kRegisterServices、kServiceDiscovery、kInit、kRun 和 kTerminate。请注意,kRun 预计会多次返回。]
[SWS_EM_01304] 服务修改 [如果进程访问的服务需要在执行 kRun 周期时被替换(例如由于不可用),则 ara::exec::DeterministicClient::WaitForActivation 应在下次调用后立即返回 kServiceDiscovery,然后继续正常的 kRun 周期。]
服务发现更新需要以实现特定的方式触发,例如通过指示服务不可用的 StartFindService 触发的回调。由于服务发现更新是在 kRun 周期内与 kRun 执行一起运行的,因此最坏情况执行时间估计和预算分配需要考虑 kRun 和 kServiceDiscovery 可能在配置的执行周期时间内顺序运行。
ara::exec::DeterministicClient::WaitForActivation 返回 kRegisterServices、kServiceDiscovery、kInit、kRun(仅第一个 kRun 周期,否则见下文)或 kTerminate 的时间点是实现特定的。在冗余执行的情况下,需要同步序列。
kRun 周期的激活行为可以由执行管理与通信管理一起按照安全概念的要求实现。执行可以通过两种不同的机制触发。
周期性激活意味着 ara::exec::DeterministicClient::WaitForActivation 基于定义的周期定期返回。
事件触发激活意味着 ara::exec::DeterministicClient::WaitForActivation 基于为进程从外部通过通信管理配置的通信事件触发器返回,例如由外部单元、由于数据到达或定时器事件生成的事件。
周期性激活和事件触发激活的同步细节在第7.6.4节中讨论。
[SWS_EM_01351] 执行周期时间 [当自上次返回 kRun(除非 kRun 周期需要被实现特定的激活控制中断或终止)以来已达到可配置的 cycleTimeValue 时,ara::exec::DeterministicClient::WaitForActivation 应返回 kRun。]
[SWS_EM_01352]{草案} 执行周期超时 [如果进程在 kRun 周期内,在自上次激活以来已超过配置的 cycleTimeValue 后调用 ara::exec::DeterministicClient::WaitForActivation,则应通知平台健康管理有关超时的信息,以启动适当的恢复操作。]
[SWS_EM_01353]{草案} 事件触发周期激活 [如果配置的 cycleTimeValue 为零,则 ara::exec::DeterministicClient::WaitForActivation 应由通信管理触发以启动下一个 kRun 周期。触发条件是实现特定的,并由通信管理评估。]
这种行为周期可用于软件锁步环境中,以初始化和触发冗余进程的执行,并在周期结束后比较结果。对于冗余执行,其执行行为和预算(激活时序、计算时间、计算资源)应在集成时明确可见,以配置执行管理。
执行管理与通信管理一起启动服务发现,因此整体行为是确定性的。可选地,例如如果软件锁步实现需要,通过通信管理接收的所有输入数据应在周期开始时可用,并保证确定性一致。
7.6.3.2 工作池
[SWS_EM_01305] 工作池 [执行管理应提供一个阻塞 API ara::exec::DeterministicClient::RunWorkerPool,以运行确定性工作池,在进程执行周期内使用。]
工作池由进程的主线程按顺序触发。ara::exec::DeterministicClient::RunWorkerPool 是阻塞的,因此主线程和工作池之间没有并行性。不允许用户进程使用正常的 POSIX 机制自行创建线程,以避免引入非确定性行为的风险。
ara::exec::DeterministicClient::RunWorkerPool 注册一个 “worker” 可运行对象及其参数对象。容器参数包含一组对象,这些对象由池中多个 worker(例如基于 POSIX 线程)调用的同一个可运行对象并行处理(参见图7.16)。这意味着确定性工作池用于处理一组容器元素,这些元素是 worker 的参数。容器中的每个元素代表一个要计算的任务。通过使用容器迭代器将元素确定性分发给各个 worker。
[SWS_EM_01306] 处理容器对象 [ara::exec::DeterministicClient::RunWorkerPool 应使用大小为 numberOfWorkers 的工作池,通过调用方法 ara::exec::WorkerRunnable::Run(输入参数 runnableObj),在输入参数容器的每个元素上顺序(使用输入参数容器的迭代器)执行。]
[SWS_EM_01307]{草案} Worker 对象 [传递给 ara::exec::DeterministicClient::RunWorkerPool 的 Worker 对象应使用公共继承从 ara::exec::WorkerRunnable 派生。]
在 ara::exec::DeterministicClient::RunWorkerPool 内部,容器元素由后台工作池迭代处理。如果可用的元素多于 worker,则会发生顺序处理。在伪代码中(忽略并行化),方法 ara::exec::DeterministicClient::RunWorkerPool 的行为如下:
std::array<WorkerThread, 4> workers;
template<typename C>
void DeterministicClient::RunWorkerPool( WorkerRunnable< typename C::value_type>& w, C& container) noexcept
{
int count = 0;
auto c = container.begin();
while(c != container.end() ) {
w.Run( *c++, workers[count++ ]);
count %= workers.size();
}
}工作池的实现和大小(即线程数)对用户是隐藏的。集成者决定实现和大小,并配置参数 numberOfWorkers。工作线程到处理器内核的分配留给操作系统。
如果所需的容器元素数量超过确定性工作池中的 worker(线程)数量,执行管理可以按顺序多次使用工作池(无限制交错),这对工作池的用户应是透明的。
为了实现数据确定性,并行 worker 需要满足某些实现属性,例如 worker 处理的各个可运行对象实例之间不允许交换数据。详细信息参见 [12]。其他更复杂的允许 worker 之间交互的解决方案是可能的,但它们会增加复杂性、降低利用率和透明度,并且容易在确定性行为方面出错。
工作池在此 API 调用者的进程上下文中运行。它被设计为执行管理的一部分,通过将其合并到 ara::exec::DeterministicClient::WaitForActivation 周期中来保证确定性行为。
在 [12] 中可以找到 worker 可运行对象的实现示例。
目标是尽可能抽象数据处理,而与实际可用的并行执行路径的数量无关。示例:一个具有 N 个相似子任务的任务(例如 N 个卡尔曼滤波器)。该任务被分配给工作池,工作池使用给定的 worker 可运行对象(在此示例中,worker 可运行对象将是卡尔曼滤波器)处理它。
工作池不能用于并行处理多个不同的任务。使用多个可能不同的显式函数(worker 可运行对象)可能会增加不必要的复杂性,并可能导致极其异构的运行时利用率,因为每个 worker 可能具有不同的计算时间。这将使必要的资源部署规划复杂化,而这对于黑盒集成是必需的。
7.6.3.3 随机数
[SWS_EM_01308] 随机数 [执行管理应提供一个 API ara::exec::DeterministicClient::GetRandom,它提供“确定性”随机数。“确定性”意味着,对于冗余执行的进程,包括在工作池中处理的可运行对象(参见 [SWS_EM_01305]),提供的随机数是相同的。]
如果从 ara::exec::DeterministicClient::RunWorkerPool 内部使用,随机数被分配给特定的容器元素,使用容器迭代器,以允许确定性冗余执行。
ara::exec::DeterministicClient::SetRandomSeed API 可用于为伪随机数生成播种,通过将其合并到 DeterministicClient::WaitForNextActivation 周期中来保证确定性行为。
不需要支持冗余执行的 DeterministicClient 实现可以提供没有特定属性的标准随机数。
7.6.3.4 时间戳
确定性用户进程可能在其 kRun 周期中周期性(参见7.6.3.1)处理输入数据时需要定时信息。使用的时间值可能会影响计算结果。因此,执行管理返回确定性时间戳,表示当前周期被激活的时间点,以及如果已知则返回下一个周期将被激活的时间点。对于冗余执行的进程(例如在锁步环境中),时间戳必须是相同的(参见7.6.2)。
[SWS_EM_01310] 获取激活时间 [执行管理应提供一个 API ara::exec::DeterministicClient::GetActivationTime,它提供一个确定性时间戳,表示当前 kRun 周期被 ara::exec::DeterministicClient::WaitForActivation(参见 [SWS_EM_01301])激活的时间点。确定性意味着,对于冗余执行的进程,时间戳是相同的。在一个周期内的后续调用应始终返回相同的值。]
[SWS_EM_01311] 激活时间未知 [如果在 kRun 周期之外调用 ara::exec::DeterministicClient::GetActivationTime,执行管理应返回 kNoTimeStamp。]
[SWS_EM_01312] 获取下一次激活时间 [执行管理应提供一个 API ara::exec::DeterministicClient::GetNextActivationTime,它提供一个确定性时间戳,表示下一个 kRun 周期将被 ara::exec::DeterministicClient::WaitForActivation(参见 [SWS_EM_01301])激活的时间点。确定性意味着,对于冗余执行的进程,时间戳是相同的。在一个周期内的后续调用应始终返回相同的值。]
[SWS_EM_01313] 下一次激活时间未知 [如果在调用 ara::exec::DeterministicClient::GetNextActivationTime 时不知道下一次激活时间,例如由于非等距事件触发激活,执行管理应返回 kNoTimeStamp。]
7.6.3.5 实时资源
为了确保时间确定性(参见7.6.1.1),即确保进程内的周期性确定性执行(参见7.6.3.1)在给定截止时间前完成,我们需要:
- 执行管理支持确定性多线程以满足高性能需求,参见7.6.3.2
- 集成者需要为进程分配适当的资源。
- 集成者需要分配适当的调度策略。标准 POSIX 调度策略(参见 [SWS_EM_01014])以外的详细信息和选项在很大程度上取决于所使用的操作系统,是供应商特定的,目前不在自适应平台规范的范围内。
- 集成者需要配置截止时间监控,可能还需要执行预算监控,以及在违规情况下的适当恢复操作。有关资源的更多详细信息,请参见7.7。
为了确保所有使用 DeterministicClient API 的进程获得足够的计算资源并能及时完成其周期,特别重要的是要知道工作池 (ara::exec::DeterministicClient::RunWorkerPool) 在 kInit 和 kRun ara::exec::DeterministicClient::WaitForActivation 周期内何时需要。此外,只有当 worker(即可用内核)的使用可以随时间均匀分布时,才能实现良好的计算资源利用率。如果集成者知道应用程序代码,分析行为并相应地配置系统应该没有问题。但是,如果第三方“黑盒”应用程序交付集成,则其资源需求需要以标准化方式描述,以便集成者对 ara::exec::DeterministicClient::WaitForActivation 周期内资源消耗的分布有一个大致的了解。
为了描述 kInit 和 kRun 周期内的预算需求,我们使用归一化值 NormalizedInstruction 来指定目标系统上的运行时消耗。
NormalizedInstruction = 运行时(秒) * 时钟频率(赫兹)
NormalizedInstruction 并不反映实际代码指令的数量,但允许描述比较资源需求。
以下参数 (DeterministicClientResource, 参见 [4] 中的 [TPS_MANI_01200]) 与描述使用 ara::exec::DeterministicClient::RunWorkerPool 的进程的计算时间预算需求相关。
每个使用 DeterministicClient 的进程需要指定两次这些参数,一次用于 kInit 周期,一次用于 kRun 周期 (DeterministicClientResourceNeeds, 和 [TPS_MANI_01199])。
-
numberOfInstructions [NormalizedInstructions]
这是在一个周期内目标系统上的归一化运行时消耗,假设 worker 将顺序执行的“最坏情况”运行时。
-
speedup = 顺序运行时间 / 并行运行时间
定义如果 numberOfWorkers(参见7.6.3.2)在物理上可用,即机器上有足够的内核来并行执行所有 worker,一个周期内的计算可以快多少。
-
sequentialInstructionsBegin [NormalizedInstructions]
这是在周期开始时的归一化顺序运行时间(大多无法并行化),在工作池主要使用开始之前。
-
sequentialInstructionsEnd [NormalizedInstructions]
这是在周期结束时的归一化顺序运行时间(大多无法并行化),在工作池主要使用结束之后。
示例
示例 7.5
进程主要在周期中间使用工作池。前 100 个(归一化)指令主要是顺序的,接下来的 275 个指令在使用工作池时受益,最后 125 个指令再次主要是顺序的。在全部 500 个指令上的平均加速比为 1.3。
numberOfInstructions = 500 numberOfWorkers = 2 speedup = 1.3 sequentialInstructionsBegin = 100 sequentialInstructionsEnd = 125
示例 7.6
进程在大部分周期中顺序运行,并且在使用工作池方面没有受益,即使用工作池的开销抵消了并行化增益。
numberOfInstructions = 200 numberOfWorkers = 2 speedup = 1 sequentialInstructionsBegin = 200 sequentialInstructionsEnd = 0
示例 7.7
进程在整个周期中充分利用了工作池。
numberOfInstructions = 200 numberOfWorkers = 3 speedup = 2.9 sequentialInstructionsBegin = 0 sequentialInstructionsEnd = 0
7.6.4 确定性同步
API ara::exec::DeterministicClient::WaitForActivation 在第7.6.3节中被描述为确定性冗余执行中的等待点。本节将提供关于周期性和事件触发激活的执行周期中同步行为的更多细节。
7.6.4.1 DeterministicSyncMaster
DeterministicSyncMaster 是一个同步控制点,通过专用通信通道(例如 ara::com)接收同步请求,并将计算出的下一个执行周期的周期信息发送给同一域中连接的 DeterministicClient。
请注意,它不限于使用 ara::com 或其他通信通道的 API,由供应商决定使用哪种。本规范仅描述与 ara::com API 的集成,用于 DeterministicSyncMaster。与其他通信 API 的集成未涵盖,可能在后续版本中指定。
图7.20显示了一个示例,说明 DeterministicSyncMaster 如何基于 ara::com 接口的请求-响应通信,控制应用程序进程的两个 DeterministicClient 的同步。
对于事件触发激活,应提供特定的同步策略。该策略高度依赖于供应商解决方案和要求,例如,仅当收到所有进程的同步请求时才将同步响应发送给 DeterministicClient。可能存在更复杂的策略,例如在给定截止时间前收到 3 个同步请求中的 2 个,也称为 M-out-of-N (MooN) 策略。
对于周期性激活,DeterministicClient 需要在执行 kInit 或 kServiceDiscovery 周期后(参见 [SWS_EM_01304] 关于服务修改)发起的第一个 ara::exec::DeterministicClient::WaitForActivation 调用进行一次同步。激活响应包括第一个 kRun 周期激活的全局时间戳,并且还应通过通道为 DeterministicClient 接收激活响应提供合理的时间缓冲。所有 DeterministicClient 将依赖本地时间计数直到达到激活时间,然后开始 kRun。进一步的 ara::exec::DeterministicClient::WaitForActivation 调用将不会发送任何同步请求,而只是在本地时间计数器达到配置的 cycleTimeValue 定义的截止时间时返回(参见 [SWS_EM_01351])。周期性激活的 kRun 周期中错过截止时间的处理在 [SWS_EM_01352] 中描述。
对于周期性和事件触发激活,在 DeterministicSyncMaster 启动之前需要定义一组参数。
[SWS_EM_01320]{草案} DeterministicClient 的数量 [连接到 DeterministicSyncMaster 的 DeterministicClient 的数量应在 DeterministicSyncMaster 初始化期间设置。]
[SWS_EM_01321]{草案} 所需同步请求的最小数量 [应为 DeterministicSyncMaster 初始化来自同一域中连接的 DeterministicClient 的所需同步请求的最小数量。]
MooN 策略定义了一个规则,用于 DeterministicSyncMaster 决定何时响应下一个执行周期的同步请求。(N) 是连接到同一域中 DeterministicSyncMaster 的进程数量([SWS_EM_01320]),(M) 是在同一域中所需的最小同步请求数量([SWS_EM_01321])。MooN 的用法可以根据冗余执行的要求进行修改。例如,当收到 (M) 个请求((M < N))时,DeterministicSyncMaster 可以忽略其余未收到的请求,并基于接收到的请求开始计算下一次激活的周期信息。周期信息封装在响应消息中,并传播给所有连接的 DeterministicClient。如果 (M) 等于 (N),这意味着在继续计算下一个周期之前,应接收来自 (N) 个 DeterministicClient 的所有请求。
请注意,对于当前版本,仅描述了 MooN 策略,其他策略的配置可能在后续版本中指定。
[SWS_EM_01322]{草案} 下一个周期的计算 [DeterministicSyncMaster 应基于 MooN 策略和接收到的同步请求计算下一次激活时间(参见 [SWS_EM_01325])。]
计算的周期信息通过响应消息发送给所有连接的 DeterministicClient(参见 [SWS_EM_01326])。基于响应消息,DeterministicClient 通过在激活时间从 ara::exec::DeterministicClient::WaitForActivation 调用返回来触发下一个执行周期。
[SWS_EM_01323]{草案} 总 kRun 循环次数 [应在 DeterministicSyncMaster 初始化期间为目标 DeterministicClient 设置 kRun 循环的总次数,以指示何时应从 ara::exec::DeterministicClient::WaitForActivation 返回 kTerminate。]
[SWS_EM_01324]{草案} 无限 kRun 循环 [kRun 循环次数设置为零应表示无限 kRun 周期计数。]
注意:用于存储 kRun 循环次数的数据类型是特定于实现的。
当前 DeterministicSyncMaster 的规范支持信号域和多个域中的冗余确定性执行。DeterministicSyncMaster 应作为时间从站工作,以便在需要计算和分发执行周期确定性时间戳时获得全局时间戳。使用 DeterministicClient 实现的进程应与 DeterministicSyncMaster 处于同一全局时间域中,这样即使它们通过网络或网关连接,也可以同步。
对于单域同步,DeterministicClient 和 DeterministicSyncMaster 在获取当前时间时都应使用本地时间资源,以保持简单和高效。可以通过调用 ara::core::SteadyClock 或 POSIX API(例如 std::chrono API)来访问本地时间。
对于多域同步,DeterministicClient 和 DeterministicSyncMaster 都应配置为使用相同的全局时间资源,例如 GPS 时间。跨网络同步的配置将在后续版本中指定。
对时间资源的安全访问保证应由策略决策点 (PDP) 和策略执行点 (PEP) 配置管理,用于时间从站和主站。例如,访问管理器可以授予 DeterministicSyncMaster 访问已配置时间主站和时间资源的权限。由于 DeterministicSyncMaster 仅公开 ara::com 和 ara::tsync 接口,因此应使用 IAM 对 ara::com 和 ara::tsync 的功能执行访问控制。
当进程在执行周期中运行时,每个周期都需要通过调用 ara::exec::DeterministicClient::WaitForActivation 进行同步。同步进程及其冗余的行为应由 DeterministicSyncMaster 执行,它可以部署在执行管理进程、软件锁步进程或单独的进程中。图7.21显示了在单独进程中运行 DeterministicSyncMaster 的示例。
软件锁步是一个可选的框架,用于确保冗余执行进程的相同行为。软件锁步框架不一定与 DeterministicSyncMaster 交互,但它们可以集成以简化控制逻辑并减少通过 ara::com 或其他专用通信通道的通信工作。例如,软件锁步可能还需要了解每个执行周期的状态,以便给出更合理和可信的比较结果。软件锁步的细节不在当前规范的范围内,仅简要讨论可能的集成架构。图7.22给出了库模式和进程模式下的软件锁步框架示例。软件锁步的细节将在后续版本中指定。
对于软件锁步的进程模式,DeterministicSyncMaster 功能可以作为库集成到软件锁步内部。对于软件锁步的库模式,它可以集成到 DeterministicSyncMaster 进程中。
图7.23和7.24说明了在进程模式和库模式下将 DeterministicSyncMaster 与软件锁步集成以用于具有两个 DeterministicSyncMaster 的跨域的可能方式示例。对于两种模式,DeterministicSyncMaster 应通过同步通道连接以做出最终决策。多个软件锁步实例是否应在不同域中运行不在本概念的范围内,因为这取决于供应商基于可用集成可能性的部署和解决方案。
7.6.4.2 同步控制消息
在本节中,我们指定控制消息的基本元素,以便基于平台供应商实现和数据结构运行冗余确定性执行。专用接口和数据结构将在后续版本中指定。
[SWS_EM_01325]{草案} 同步请求消息 [用于 DeterministicClient 激活的 ara::exec::DeterministicClient::WaitForActivation 应向连接的 DeterministicSyncMaster 发送同步请求消息。]
同步请求应至少包含以下数据成员:
- 服务 ID:发送同步请求的 DeterministicClient 中服务骨架的服务 ID。
- 实例 ID:通过服务骨架发送同步请求的进程的实例 ID。
- 前一个周期的激活时间戳:前一个周期的激活用于计算下一个周期。
- 当前周期的代码:当前周期的类型用于确定下一个执行周期的类型。可能的代码有 kServiceDiscovery、kInit、kRun。
- 当前循环的计数:执行循环的次数用于确定
ara::exec::DeterministicClient::WaitForActivation何时应返回 kTerminate。
成员的数据类型是特定于实现的,因为接口是两个平台特定元素之间的接口。
[SWS_EM_01326]{草案} 同步响应消息 [当应用同步策略匹配时,DeterministicSyncMaster 应向所有连接的 DeterministicClient 发送同步响应消息。]
同步响应应至少包含以下数据成员:
- 服务 ID:发送同步响应的 DeterministicSyncMaster 中服务骨架的服务 ID。
- 实例 ID:运行 DeterministicSyncMaster 的进程的实例 ID,该进程通过服务骨架发送同步响应。
- 下一个周期的激活时间戳:计算出的下一个执行周期的激活时间戳。
- 下一个周期的代码:确定的下一个周期的代码。可能的值为 kRun、kServiceDiscovery 和 kTerminate。当需要服务修改时返回 kServiceDiscovery 代码(参见 [SWS_EM_01304])。当达到 kRun 总循环次数或执行管理请求终止时(参见 [SWS_EM_01404]),返回代码 kTerminate。
[SWS_EM_01327]{草案} 等待点 API 的返回 [ara::exec::DeterministicClient::WaitForActivation 调用不应返回,直到本地时间计数器达到同步响应消息中为下一个 kRun 周期发送的激活时间戳。]
7.7 资源限制
尽管系统中特定自适应应用程序的行为正确,但确保任何潜在的不正确行为以及任何不可预见的交互不会导致系统无关部分发生干扰是很重要的 [RS_EM_00002]。由于 AUTOSAR 自适应平台也力求允许在同一台机器上整合多个功能,因此确保免于干扰是一个关键属性。
然而,AUTOSAR 自适应平台无法以标准化方式支持本章概述中的所有机制,因为其可用性高度依赖于所使用的操作系统。
此外,重要的是要考虑执行管理仅负责机器的正确配置。然而,强制执行相关限制通常由操作系统或其他应用程序(如持久性服务)完成。
在本版本中,一些可以标准化的机制尚未定义。
7.7.1 资源配置
本节概述了向建模进程分配资源。本规范中考虑的资源包括:
- RAM(例如,用于代码、数据、线程堆栈、堆)
- CPU 时间
其他资源,如持久存储或 I/O 使用,也相关,但目前不在本规范范围内。
通常,我们需要区分两种资源需求值:
- 最小资源,需要保证进程能够达到其运行状态并执行其基本功能。
- 最大资源,可能临时需要,并且任何时候都不应超过,否则可以假定发生错误。
以下利益相关者参与资源管理:
应用程序开发人员
应用程序开发人员应了解建模进程在特定时间内执行其任务需要多少内存(RAM)和计算资源。这需要在应用程序描述(可以是执行清单的预集成阶段)中指定,并移交给集成者。其他约束,例如完成特定任务的截止时间(例如周期时间),通常也将在此处配置。
然而,确切的要求可能取决于特定的用例,例如:
- RAM 消耗可能取决于预期用途,例如视频过滤器可能配置为不同的视频分辨率,因此资源需求可能在一个范围内变化。
- 所需的计算能力取决于处理器类型。即,资源需求需要转换为在该特定硬件上的计算时间。可能的并行线程在不同内核上的执行也需要在此考虑。
因此,虽然应用程序开发人员应该能够提供关于资源消耗的估计,但无法脱离上下文提供精确的使用量。
集成者
集成者了解特定平台及其可用资源和约束,以及与要配置的建模进程可能同时运行的其他应用程序。集成者应向可以同时活动的应用程序分配可用资源,这与状态管理配置密切相关,参见第7.5节。如果在任何给定时间没有足够的资源来满足所有正在运行的建模进程的最大资源需求,假设建模进程实际使用了这些资源,则必须考虑几个步骤:
- 根据安全性和功能需求,为建模进程分配资源关键性。
- 取决于操作系统,可以为进程或进程组分配设计上无法超过的最大资源(例如 Linux cgroups)。
- 必须应用调度策略,以便高关键性进程的线程获得有保证的计算时间并在截止时间前完成,而低关键性进程的线程可能不会。详细信息参见第7.7.3.1节。
- 如果在任何给定时间可能并行运行的所有进程的总计最大 RAM 需求超过了可用 RAM,则无法通过优先级轻松解决此问题,因为低关键性进程的内存分配不能仅仅被移除而不影响进程。然而,应确保高关键性进程在任何时候都能随时访问其最大资源,而较低关键性进程需要共享剩余资源。详细信息参见7.7.3.4。
基于以上,所有资源配置元素都应在平台集成期间配置,很可能由集成者配置。为了对这些配置元素进行分组,我们定义了 ResourceGroup。它可能配置了几个属性,以限制在该组中运行的应用程序。随后,每个建模进程都需要属于一个 ResourceGroup,阐明应用程序在系统级别将如何被约束。
[SWS_EM_02102]{草案} 内存控制 [如果配置中定义了,执行管理应在从该 ResourceGroup 加载进程之前,为属于每个 ResourceGroup 的所有进程配置全局可用的最大 RAM 量。]
如果 ResourceGroup 没有配置 RAM 限制,则进程仅受其隐式内存限制的约束。
[SWS_EM_02103]{草案} CPU 使用控制 [如果配置中定义了,执行管理应在从该 ResourceGroup 加载进程之前,为属于每个 ResourceGroup 的所有进程配置全局可用的最大 CPU 时间。]
如果 ResourceGroup 没有配置 CPU 使用限制,则进程仅受其隐式 CPU 使用限制(优先级、调度方案…)的约束。
7.7.2 资源监控
在技术可行的范围内,应始终控制进程实际使用的资源。对于整个系统,此活动的监控部分由操作系统完成。有关 CPU 时间监控的详细信息,请参见7.7.3.1。有关 RAM 监控的详细信息,请参见7.7.3.4。监控能力取决于所使用的操作系统。根据系统要求和安全目标,必须选择并相应配置适当的操作系统,并结合平台健康管理提供的其他监控机制(例如执行截止时间)。
资源监控可以服务于多个目的,例如:
- 检测被监控进程的错误行为,以启动适当的恢复操作,如进程重启或状态更改,以维持提供的功能并保证功能安全。
- 通过将错误进程与未受影响的进程隔离来保护系统的其他部分,以避免资源短缺。
对于试图超过其配置的最大资源需求(参见7.7.1)的进程,以下替代方案之一有效:
- 资源限制违规或错过截止时间被视为故障,可能需要启动恢复操作。因此,将特定的违规报告给状态管理,然后状态管理启动预先配置的恢复操作。这将是确定性子系统(参见7.6.1)的标准选项。
- 对于没有硬性截止时间的建模进程,有时可以在没有专用错误恢复操作的情况下缓解资源违规,例如通过中断执行并在稍后时间点继续。
- 如果操作系统提供了一种通过设计限制进程或进程组资源消耗的方法,通常不需要显式的外部监控,甚至通常不可能。相反,限制机制可确保封闭进程内的故障不会影响系统其他部分的资源可用性。当使用此类设计限制时,仍然可以使用监控机制来使平台受益,但不是必需的。在 AUTOSAR 自适应平台中,自监控和进程外监控目前不在范围内。
7.7.3 应用级资源配置
我们需要能够配置最小、有保证的资源(RAM、计算时间)和最大资源。如果需要时间确定性或完全确定性,则最大资源需求是有保证的。
7.7.3.1 CPU 使用
CPU 使用由其线程代表进程。一般来说,操作系统使用每个线程配置的某些属性来决定何时运行它,并另外约束一组线程,使其使用的 CPU 时间不超过定义的数量。由于线程可能在运行时创建,因此只能由执行管理配置第一个线程。
7.7.3.2 核心亲和性
[SWS_EM_02104] 核心亲和性 [执行管理应将进程初始线程的核心亲和性配置为将其限制在系统中的某个核心子集。]
需求 [SWS_EM_02104] 允许将进程的初始线程(进程的 “main” 线程)绑定到某些核心 [SWS_OSI_01012]。取决于操作系统的能力,子集可以是单个核心。如果操作系统不支持绑定到特定核心,则唯一支持的子集是整个核心集。
7.7.3.3 调度
当前可用的符合 POSIX 的操作系统提供 POSIX 所需的调度策略,并且在大多数情况下提供额外的但不同且不兼容的调度策略。这意味着,目前所需的调度属性需要根据所选操作系统单独配置。
此外,调度策略是按线程定义的,POSIX 标准允许在运行时使用 pthread_setschedparam() 修改给定线程的调度策略。因此,AUTOSAR 自适应平台目前无法强制执行整个进程的特定调度策略,只能强制执行其第一个线程。
[SWS_EM_01014] 调度策略 [执行管理应支持在启动进程时根据执行清单提供的信息配置调度策略。]
有关这些策略的详细定义,请参阅 [13]。请注意,SCHED_OTHER 应被视为非实时调度策略,该策略的实际行为是特定于实现的。不应假定调度行为在不同的 AUTOSAR 自适应平台实现之间兼容,除了在给定实现中它是一种非实时调度策略。
[SWS_EM_01041] 调度 FIFO [执行管理应能够使用策略 SCHED_FIFO 配置 FIFO 调度。] [SWS_EM_01042] 调度 Round-Robin [执行管理应能够使用策略 SCHED_RR 配置轮询调度。] [SWS_EM_01043] 调度 Other [执行管理应能够使用策略 SCHED_OTHER 配置非实时调度。]
请注意,这里指定的调度策略是最小集合。取决于操作系统,可能会有更多可配置的调度策略。
虽然调度策略不是保证完全确定性的充分方法,但它们有助于改善确定性。虽然目标是限制进程的 CPU 时间,但调度策略适用于线程。
请注意,虽然执行管理将确保正确配置第一个线程(调用 main() 函数的线程),但正确配置辅助线程是进程本身的责任。
[SWS_EM_01015] 调度优先级 [执行管理应支持在启动进程时根据执行清单提供的信息配置调度优先级。]
7.7.3.3.1 资源管理
通常,对于确定性行为,所需计算时间是有保证的,违规被视为错误,而尽力而为子系统则更健壮,可能能够缓解偶发的违规,例如在下一次激活时继续计算,或提供质量较低的结果。这意味着,如果时间(例如截止时间或运行时预算)监控到位,对确定性子系统和尽力而为子系统的偏差反应是不同的。
事实上,甚至可能没有必要监控尽力而为子系统,因为它们根据定义只执行可能不成功的功能。这导致了一种架构,其中监控是一个可选的、已配置的属性。
然而,剩下的关键属性是保证特定进程或进程集不能对其它进程的行为产生不利影响。
为了保证整个系统的完全确定性,确保免于干扰很重要,ResourceGroup 有助于确保这一点。
[SWS_EM_02106] ResourceGroup 分配 [执行管理应根据其 ResourceGroup 成员身份配置进程。]
7.7.3.4 内存预算和监控
为了实现一个功能,进程需要有一定数量的内存可供使用(主要是代码、数据、堆、线程堆栈)。然而,在其执行过程中,并非所有这些内存始终都需要,因此操作系统可以利用此属性按需提供这些内存范围,并在不再使用时将内存提供给其它进程。
虽然这在系统灵活性和内存效率方面具有明显优势,但它也妨碍了时间确定性和完全确定性:当之前未使用的内存范围现在应该可用时,操作系统可能需要执行一定量的潜在无界活动以使该内存可用。通常,相反的情况也可能发生,即移除作用域进程之前可用(但未使用)的内存,使其可供其它进程使用。这不利于整个系统的确定性。
执行管理应确保确定性进程可能使用的整个内存范围在相应进程执行的开始和整个持续时间内都可用。
未配置为确定性的应用程序可以按需映射。
为了在进程执行开始时提供足够的内存,可能需要为每个进程定义一些属性。
[SWS_EM_02107]{草案} 最大堆 [执行管理应配置进程的最大堆使用量。]
堆内存用于进程内的动态内存分配,例如通过 malloc()/free() 和 new/delete。
[SWS_EM_02108]{草案} 最大系统内存使用量 [执行管理应配置进程的最大系统内存使用量。]
系统内存可用于创建额外资源,如文件句柄或信号量,以及创建新线程。
[SWS_EM_02109]{草案} 进程预映射 [如果相应的执行清单需要,执行管理应预映射进程。]
完全预映射建模进程可确保代码和数据执行不会因其首次执行时按需加载而延迟。这有助于在系统启动和首次执行阶段提供时间确定性,同时也有助于处理错误情况的代码可以被预加载并保证可用。此外,预映射避免了后期可能出现文件系统损坏且部分建模进程可能无法再加载的问题。
7.7.3.5 工作文件夹
进程的工作文件夹不通过配置定义,而是有意留作实现特定元素。所需的 PSE51 POSIX 配置文件没有定义(自适应)应用程序可以为使用文件路径名的任何函数(例如,open)使用路径或文件参数,而是仅指定对象的名称而不隐含任何文件系统语义。
7.8 容错
7.8.1 引言
什么是容错?
在大型软件系统中处理故障的方法称为容错。
执行管理所采用的模型在 [14] 中概述。
本节提供了关于容错概念应用于执行管理的背景,以及这对整体平台实例的可信性的贡献视角。
平台范围面向服务架构的容错方面不在本文档范围内,且不予进一步讨论。
7.8.2 范围
执行管理对 AUTOSAR 自适应平台的整体系统行为具有至关重要的影响。
执行管理内部错误功能的影响可能非常严重,具体取决于操作模式和故障类型。例如,执行管理识别出的故障可能具有局部影响,仅影响独立进程,或者可能成为机器范围故障的根本原因。
因此,不仅需要指定正确的行为,还需要在出现偏差时引入替代行为。
此类机制解决了机器和进程生命周期管理过程中出现的广泛关注点。
AUTOSAR 自适应平台架构由两个层级组成:应用程序和平台实例。应用程序层构成协同应用程序,旨在满足整体系统需求目标,并代表车辆环境中的服务层。平台实例层作为提供基本能力和平台级服务的可重用资产。因此,执行管理内部的容错需要处理这两个层级。
7.8.3 威胁模型
导致软件(无论是应用程序还是平台实例)行为不正确的主要威胁是系统性缺陷或故障的存在,即在设计阶段引入并在部署前保持休眠状态的故障。其他故障来源包括物理故障(例如随机硬件故障),它们可能影响资源分配和正确执行,以及可能成为不正确状态转换请求来源的交互故障。
从执行管理的角度来看,当请求得到的功能组状态或此类组合时,就会发生故障激活。由于故障的性质不同,它们可能导致各种类型与预期功能行为的偏差,并最终导致错误的系统功能,无论是在正确计算结果还是时间响应方面。
通常,容错机制的实施基于两个一致的步骤——错误检测和后续的错误恢复。设计阶段活动中错误检测的主要焦点,因此本规范中容错的重点是分析潜在的故障模式以及随后应纳入实现的错误检测机制。
相比之下,错误恢复包括应采取的行动,以恢复系统状态,使系统能够再次提供正确的服务。错误检测和恢复操作的绑定应是平台范围容错模型的主题。
注意:本节的其余部分将在本规范的下一版本中进行阐述。容错机制的提供将考虑可能的故障,它们如何导致执行管理内的错误,以及为确保错误检测而引入的机制。
7.8.4 执行管理内部错误处理
从系统设计的角度来看,拥有一个执行管理/操作系统内部的不可恢复状态是有用的,当执行管理没有其他行动方案时可以进入该状态。不可恢复状态仅由执行管理触发。
[SWS_EM_02032]{草案} 进入不可恢复状态时,[执行管理应调用预清理操作。]
[SWS_EM_02033]{草案} 执行预清理操作后,[所有由执行管理的进程应被关闭。]
[SWS_EM_02034]{草案} 在所有由执行管理的进程终止后,[应调用后清理操作。]
调用预清理和后清理功能的机制是平台特定的。每个阶段应采取哪些操作没有要求。
7.9 安全
7.9.1 可信平台
从安全角度来看,确保在自适应平台上执行的所有软件都是可信的至关重要,即确保软件的完整性和真实性。执行管理作为负责进程创建的实体应承担此任务。
可信自适应平台的关键要求是机器上存在一个可信锚点,该锚点根据定义是可信的(因此有替代名称“信任根”)。可信锚点通常实现为存储在安全环境中的公钥,例如在不可修改的持久内存中或在 HSM 中。信任必须通过适当的方式(例如信任链)传递给执行管理。如果机器没有表现出可信锚点,则无法确保自适应平台是可信的。
[SWS_EM_02299] 可信锚点的可用性 [如果机器上没有可用的可信锚点,则可以忽略以下要求:[SWS_EM_02300]、[SWS_EM_02301]、[SWS_EM_02302]、[SWS_EM_02303]、[SWS_EM_02304]、[SWS_EM_02305]、[SWS_EM_02306]、[SWS_EM_02307]、[SWS_EM_02308]、[SWS_EM_02309]。]
有多种方法可以验证自适应平台的完整性和真实性。可信平台可以例如(但不限于)通过以下方式实现:
- 由引导加载程序验证整个 Ramdisk
- 验证单个可执行文件和数据文件,例如使用操作系统功能或可信的第三方进程
- 验证加载时的单个内存页,例如使用操作系统功能或可信的第三方进程
[SWS_EM_02300] 已处理机器清单的完整性和真实性 [执行管理应确保检查已处理机器清单的完整性和真实性。]
[SWS_EM_02301] 每个可执行文件的完整性和真实性 [执行管理应确保对于即将启动的每个进程,检查可执行文件本身的完整性和真实性。]
[SWS_EM_02302] 共享对象的完整性和真实性 [执行管理应确保对于即将启动的每个进程,检查每个相关共享对象的完整性和真实性。]
[SWS_EM_02303] 已处理执行清单的完整性和真实性 [执行管理应确保对于即将启动的每个进程,检查其相应已处理执行清单的完整性和真实性。]
[SWS_EM_02304] 已处理服务实例清单的完整性和真实性 [执行管理应确保对于即将启动的每个进程,检查其相应已处理服务实例清单的完整性和真实性。]
从安全角度来看,选择这些项的理由如下:
- 可执行文件:修改可执行文件本身允许攻击者在机器上执行任意代码;
- 清单:机器清单、执行清单和服务实例清单描述了应该执行什么以及如何执行,因此是自适应平台的一个明显攻击向量;
- 共享对象:共享对象包含在进程上下文中执行的可执行代码。修改后的共享对象可能被用来危及系统。
为了建立一个可信平台,必须确保只有可信软件被启动。因此,系统设计者必须确保执行管理被可信地启动。例如,这可以通过如 [15] 中描述的信任链来实现。
执行管理反过来应确保在自适应平台上的所有可执行代码在执行之前都经过身份验证。完整的经过身份验证的启动序列如下所示:
应用程序存储的持久数据的完整性和真实性在此不考虑。功能集群 Persistency 负责处理这些数据的完整性。
7.9.1.1 处理失败的真实性检查
如果完整性和真实性已成功验证,系统应继续其常规启动过程。但是,如果完整性和真实性检查失败,执行管理应提供一个配置选项,说明如何继续启动过程。
[SWS_EM_02305] 失败的真实性检查 [执行管理应提供两种模式来处理失败的真实性检查:监控模式和严格模式。]
两种模式的配置通过机器清单完成。配置选项仅在已处理机器清单的完整性和真实性得到验证后才被处理。
[SWS_EM_02306]{草案} 机器清单 [如果已处理机器清单的完整性或真实性检查失败,执行管理应停止自适应平台的启动序列。]
7.9.1.1.1 监控模式
在监控模式下,执行完整性和真实性检查,但启动过程不受影响。因此,即使文件系统已被破坏,自适应平台也会启动。
当集成者希望系统持续运行,即使平台不被认为是可信的时,监控模式很有用。在这种情况下,集成者可能会使用自适应 AUTOSAR 范围之外的附加措施,例如在使用支持此功能的 HSM 时限制密钥访问。
在开发阶段,当自适应平台频繁更改且保持身份验证标签(例如签名)有效是一项繁琐的任务时,监控模式也很有用。
7.9.1.1.2 严格模式
在严格模式下,自适应平台确保不执行任何进程,如果相应可执行文件、清单或链接库的完整性和真实性无法验证。
[SWS_EM_02307]{草案} 严格模式 - 执行清单 [在严格模式下,如果相应已处理执行清单的完整性或真实性检查失败,执行管理不应启动可执行文件的执行。]
[SWS_EM_02308]{草案} 严格模式 - 服务实例清单 [在严格模式下,如果至少一个相应已处理服务实例清单的完整性或真实性检查失败,执行管理不应启动可执行文件的执行。]
[SWS_EM_02309]{草案} 严格模式 - 可执行文件 [在严格模式下,仅当其完整性和真实性检查成功时,执行管理才应执行代码。]
可执行代码可以由可执行文件提供,也可以由可执行文件链接的共享对象提供。
示例:考虑一个处于严格模式的自适应平台。执行管理在成功验证可执行文件、其相关共享对象及其已处理执行清单的完整性和真实性后,已启动多个可执行文件。现在,执行管理想要启动另一个可执行文件,但该可执行文件的真实性检查失败。执行管理不会启动此可执行文件,因为它不可信。但通过真实性检查的其他可执行文件可以继续运行。当执行管理尝试启动另一个可执行文件时,只要所有真实性检查都通过,就可以启动。
7.9.2 身份和访问管理
遵循“最小权限原则”,自适应平台中引入了身份和访问管理 (IAM)。IAM 允许为建模进程分配访问公共功能集群接口的最小权限集。因此,建模进程在运行时必须是可识别的,以便相应地查找和执行权限。执行管理基于建模进程启动进程。因此,执行管理能够维护两者之间的关联。执行管理通过揭示有关此关联的信息来支持 IAM。这允许 IAM 在操作系统的帮助下在运行时验证进程。
[SWS_EM_02400]{草案} 分配给进程的 IAM 配置的属性 [执行管理应在进程创建期间将建模进程身份与进程关联。]
身份的形式是特定于实现的,但可以是例如进程标识符、加密令牌、用户 ID 等。
根据实现要求,执行管理可以公开允许 IAM 检索有关进程和建模进程身份之间关联信息的接口。此接口的具体形式是实现定义的。