31、使用Ada95软件的应用层(第7层)路由交换机

使用Ada95软件的应用层(第7层)路由交换机

1. 选择Ada的原因及应用方式

1.1 选择Ada的原因

选择Ada作为AppSwitch™软件的编程语言,是为了实现高可靠性和可移植性。该软件必须首次运行就正常工作,并且能在出现故障和进行软件重新配置时持续执行。由于AppSwitch™软件预期有较长的使用寿命,所以编程语言需要能够在不同的目标机器及其不同代产品之间进行移植。Ada具备高可靠性和可移植性所需的语言特性,包括强类型、面向对象编程、多任务处理和异常处理。

1.2 工具链的选择

选择GNAT作为工具链,因为它基于GCC,而GCC针对ARC处理器。Ada工具运行在Solaris和Linux上,目标平台包括Motorola MPC 860、ARC和Linux。工具链设计为通过网络运行,将Solaris通过一台运行Linux或Windows NT™的独立PC连接到AppSwitch™,这台PC充当AppSwitch™的逻辑控制台。通常,通过一个窗口对控制台PC进行低级别的加载和监控控制,通过另一个运行gdb的emacs窗口进行语言级别的加载和监控控制。

1.3 Ada在不同组件中的应用

1.3.1 转发引擎

Ada在转发引擎架构中的应用非常直接。由于主要软件结构是一个轮询循环,且不处理中断,因此只需要一个线程,转发引擎软件封装在一个主要的Ada子程序中,不需要底层的Ada运行时系统。出于性能考虑,所有应用策略例程和轮询循环中的快速路径采用高度优化的手工汇编代码,其余软件用Ada编写,比例约为10%汇编代码和90% Ada代码。

1.3.2 广域网子系统

Ada在广域网子系统架构中的应用同样直接。一个Ada主程序封装了轮询循环,更新内部时钟的中断用汇编语言手工编写,对Ada主程序透明,因此也不需要底层的Ada运行时系统。大约90%的代码用Ada编写,其余部分在汇编代码和C代码之间分配。

1.3.3 后台引擎

后台引擎架构非常适合使用Ravenscar Profile。架构中的所有任务都是静态定义的,且不会嵌套在其他子程序或任务中。后台引擎对Ada任务通信和同步功能的使用有限,任务之间的通信可以通过队列和信号完成,这些都可以实现为受保护对象。所有受保护对象要么没有入口,要么只需要一个入口调用。单入口受保护对象常被用作事件队列,事件由一个或多个任务入队,由单个任务处理。虽然后台引擎的架构与Ravenscar Profile有很多相似之处,但由于后台引擎软件并非严格的硬实时应用,所以在某些方面有所不同,去除一些限制可以使软件架构更灵活,以适应数据通信的动态特性。

1.4 扩展模块与面向对象编程

1.4.1 扩展模块的构建与执行

扩展模块在Ada中表示为一个包,必须包含识别模块、定义其提供的接口以及支持其执行的元素。具体如下:
- 识别模块 :每个模块必须有模块名称(即Ada包名)和模块版本号(即’Body_version属性)。
- 定义接口 :每个模块必须有一个或多个接口,这些接口是接口“模板”类型的具体类型扩展。
- 支持注册 :每个模块必须有一个ModuleBody,用于使ModuleObjectMgr获取扩展模块提供的接口。模块包体中的语句序列在完成自身详细说明后,会实际调用将扩展模块注册到ModuleObjectMgr。
- 支持实现 :模块还需要StateBlock对象,用于包含执行状态,可选地包含任务、队列和其他受保护对象。

模块包的具体构成如下表所示:
| 包元素 | 包规范 | 包体 |
| — | — | — |
| 接口“模板”类型的具体扩展 | 一个或多个 | 所有实现 |
| 状态块类型的具体扩展 | 一个或多个 | 所有实现 |
| 模块体类型的具体扩展 | - | 实现 |
| 任务、队列和其他受保护对象 | - | (可选) |
| 描述模块名称和其他属性的全局值 | - | 有 |
| 注册模块体对象的详细代码 | - | 有 |

1.4.2 模块体类型和类

ModuleBody是与所有扩展模块唯一关联的对象类的根。对于每个扩展模块,会有一个ModuleBody根类型的具体类型扩展,称为MyModuleBody,并为该模块声明一个MyModuleBodyObject,用于完成活动扩展模块的注册。为所有ModuleBody对象定义了两个抽象操作:
- MakeAnInterface :创建一个接口对象,使客户端能够访问模块对该接口“模板”的实现,客户端必须提交接口“模板”的ID。
- IsAnInterface :验证模块是否生成了该接口对象。

1.4.3 模块对象管理器

ModuleObjectMgr是核心软件组件,它通过模块提供的接口对象使扩展模块对其他扩展模块可用。其主要服务包括:
- 从所有扩展模块的外部数据库创建所有扩展模块的模块对象内部数据库。
- 下载并动态绑定所有请求(活动)模块对象的可执行代码,动态绑定仅限于解析加载的可执行代码中的所有外部引用,并找到可执行代码的adainit和adafinal入口点。
- 应请求将新的扩展模块和现有扩展模块的新版本添加到外部和内部数据库。
- 应请求从外部和内部数据库中删除扩展模块。
- 为其他模块提供接口服务。

模块对象在其执行代码加载并绑定到内存,且有对其ModuleBodyObject的有效引用时才完全激活。常见接口为普通客户端模块提供以下重要操作:
- GetIF :从由Ada包名标识的模块对象的ModuleBody中返回一个接口对象(与由其InterfaceID标识的接口“模板”类型相关联的类中)。
- GetAnotherIF :通过使用现有接口对象,从模块对象的ModuleBody中返回另一个接口对象(与由其InterfaceID标识的接口“模板”类型相关联的类中)。
- RegisterModuleBody :通知ModuleObjectMgr模块已完成详细说明,模块对象已完全激活。

1.4.4 接口

所有模块提供的接口都是接口类中接口“模板”类型的具体类型扩展。接口类的层次结构如下:
- 抽象接口类型 :是接口对象层次类的根,定义了接口对象包含的内容和所有接口对象必须具备的一组基本通用操作,如GetState(返回接口对象的状态块对象)、GetModule(返回提供实际接口的模块对象)和Release(释放接口对象),这些基本操作有明确的实现,且不允许被接口类的类型扩展覆盖。
- 抽象接口“模板”类型 :定义了模块接口的独特操作,每个“模板”类型定义了其具体类型扩展必须提供的所有操作,“模板”类型是支持这些操作具体实现的接口对象“子类”的根。接口“模板”类型是抽象的,不能声明其对象,为每个“模板”类型定义的操作可以是抽象的或“空”实现,具体取决于具体类型扩展中操作被覆盖的频率。
- 具体类型扩展 :如果模块希望提供由接口“模板”类型定义的接口,必须声明该接口“模板”类型的具体类型扩展,每个具体类型扩展为其覆盖的所有“模板”操作提供实际实现,接口对象由这些具体类型扩展之一进行类型定义。

当客户端模块希望使用由接口“模板”类型定义并由特定扩展模块实现的操作时,只需在该扩展模块提供的接口对象上调用该操作,操作将分派到相应的实现。

下面是接口层次结构的mermaid流程图:

graph TD;
    A[抽象接口类型] --> B[抽象接口“模板”类型];
    B --> C[具体类型扩展];
    C --> D[接口对象];

1.5 扩展模块的最终说明

扩展模块的概念与Ada中的分区概念有很多相似之处,Top Layer打算利用这种相似性,通过添加进程来封装扩展模块的执行,将Ada运行时系统的实现扩展为像处理分区一样处理扩展模块,扩展模块/分区/进程是否扩展以处理分布式应用还有待观察。

2. 遇到的障碍与经验教训

2.1 遇到的障碍

在使用Ada的过程中,面临了三个重大挑战:
- 学习曲线陡峭 :Ada并非构建数据通信产品软件的常用语言,除CTO外,团队中无人了解或使用过Ada。对于经验丰富的软件工程师来说,学习Ada被认为是不必要的挑战,且对他们的简历没有帮助。为应对这一挑战,采取了以下措施:
1. 创始人坚信Ada是合适的选择,并坚持使用。
2. 聘请全职Ada专家进行内部强化培训和推广,专家与其他工程师并肩工作,理解他们的困难。
3. 努力使Ada在目标系统上技术可行,提供可靠且性能良好的工具链,减少学习阻力和挫折感。
- ARC处理器的工具链不完整 :1998年初,自由软件基金会存档中有针对ARC处理器的GCC后端,但仅部分完成。经过研究,在1998年秋初决定自行完成GCC后端的开发,并得到了两位GCC技术顾问的帮助。开发分两个阶段进行:首先对现有GCC后端表进行补丁,纠正最严重的问题;然后创建全新的GCC表,更系统、高效地将GCC针对ARC。目前,新的GCC目标正在测试中,这一努力在技术和士气方面都取得了回报。
- ARC的运行时系统操作系统不足 :唯一针对嵌入式系统的公共领域Ada运行时系统RTEMS被认为过于通用和庞大,不适合后台引擎。将RTEMS与目标集成并进行精简的工作量与实现一个Ravenscar Profile运行时系统相当,且对其了解不如自定义实现深入。经过仔细考虑,决定凭借自身经验丰富的工程人才和与Ada Core Technologies的密切合作,进行Ada运行时系统的实现。两名工程师花了约16周时间完成了运行时软件的构建和测试。

2.2 经验教训

以下是一些经验教训的总结,不分先后顺序:
- 未使用或有限使用的语言特性
- 实数类型 :浮点运算成本过高,仅允许在预定义时间操作中使用Duration。
- 附件F、G :不适用于此应用。
- 预定义I/O :过于重量级,而是在现有闪存磁盘设备模块之上构建了低级I/O包。
- 附件E、H :目前不适用于此应用,未来可能根据产品线方向和实现技术重新考虑。
- 返回无约束对象的函数 :这些函数需要使用辅助栈,成本过高,这也限制了动态大小字符串的连接运算符的使用。
- 动态切片和聚合 :由于缺乏优化,这些特性成本很高。
- 长度属性 :应用于动态大小数组时,由于需要测试零长度数组,成本变得很高。
- 使用有限的特性 :由于用户对这些特性的了解不足,使用有限,包括子泛型单元、形式包参数和使用类型子句。
- 广泛使用的特性
- 面向对象编程 :加强了模块、接口和状态块之间的关系。
- Root_Storage_Pool类 :支持全面内存管理的重要机制。
- Controlled和Limited_Controlled类 :管理内存的另一个重要机制。
- 与C接口 :便于使用大量遗留和第三方软件。
- 所有表示和硬件接口特性 :显而易见的需求。
- Assert编译指示 :GNAT实现定义的特性,在测试中多次证明了其价值。

此外,还得到了以下几点重要启示:
- 定义使用指南 :Ada为新用户和普通用户提供了太多选择,新用户难以理解众多语言选择的细微差别,容易做出错误选择,导致性能不佳,强化了Ada是臃肿语言的印象。因此,必须为Ada的成功使用定义针对应用领域和工具链的指南。
- 购买支持和维护 :工业强度软件开发没有免费的编译器,需要购买适当的支持维护,并投入专门资源使工具链适用于软件开发。
- 考虑嵌入式需求 :基于工作站的工具链不一定适用于嵌入式软件,其实现选择可能会剥夺嵌入式软件产品所需的优化,导致嵌入式软件开发必须对语言特性进行不必要的限制。
- 支持新用户 :新用户使用Ada编译器时会感到沮丧,因为他们习惯了其他编译器不那么挑剔。在新用户调整期间,需要不断保证这些挑剔在软件调试和测试时是值得的,同时提供更详细的编译器诊断信息和良好语言特性选择的指南。
- 注意泛型实例化的内存占用 :频繁实例化的泛型会消耗大量内存,此时值得重新审视泛型实现的设计,找到“共享”代码内核,以减少实例化的内存占用。

下面是一个总结使用和未使用语言特性的表格:
| 特性分类 | 特性名称 | 使用情况 | 原因 |
| — | — | — | — |
| 未使用或有限使用 | 实数类型 | 有限使用 | 浮点运算成本高 |
| 未使用或有限使用 | 附件F、G | 未使用 | 不适用于应用 |
| 未使用或有限使用 | 预定义I/O | 未使用 | 过于重量级 |
| 未使用或有限使用 | 附件E、H | 未使用 | 目前不适用 |
| 未使用或有限使用 | 返回无约束对象的函数 | 未使用 | 成本过高 |
| 未使用或有限使用 | 动态切片和聚合 | 未使用 | 缺乏优化 |
| 未使用或有限使用 | 长度属性 | 有限使用 | 应用于动态数组成本高 |
| 使用有限 | 子泛型单元 | 有限使用 | 用户了解不足 |
| 使用有限 | 形式包参数 | 有限使用 | 用户了解不足 |
| 使用有限 | 使用类型子句 | 有限使用 | 用户了解不足 |
| 广泛使用 | 面向对象编程 | 广泛使用 | 加强模块关系 |
| 广泛使用 | Root_Storage_Pool类 | 广泛使用 | 支持内存管理 |
| 广泛使用 | Controlled和Limited_Controlled类 | 广泛使用 | 管理内存 |
| 广泛使用 | 与C接口 | 广泛使用 | 便于使用遗留软件 |
| 广泛使用 | 表示和硬件接口特性 | 广泛使用 | 满足硬件需求 |
| 广泛使用 | Assert编译指示 | 广泛使用 | 在测试中证明价值 |

下面是一个mermaid流程图,展示应对障碍的措施:

graph LR;
    A[学习曲线陡峭] --> B[创始人坚持使用];
    A --> C[聘请专家培训];
    A --> D[使工具链可行];
    E[工具链不完整] --> F[自行开发后端];
    F --> G[分阶段开发];
    H[运行时系统不足] --> I[自定义实现];

综上所述,虽然在使用Ada的过程中遇到了诸多挑战,但通过努力克服了这些障碍,并积累了宝贵的经验教训。这些经验对于后续使用Ada进行软件开发具有重要的指导意义。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值