RTOS诊断和错误检查

RTOS diagnostics and error checking

查看RTOS显示系列

错误处理不太可能是任何用于嵌入式系统应用程序的操作系统的主要功能。这是资源限制的必然结果,而且所有嵌入式系统都有某种限制。这也是合乎逻辑的,因为只有有限数量的嵌入式系统才有机会像桌面系统一样工作,即为用户提供一个机会,以便在发生异常事件时决定下一步要做什么。

在Nucleus SE中,大致有三种类型的错误检查:

对所选配置进行“健全性检查”的功能-只是为了确保所选选项的一致性

可选地包含用于检查运行时行为的代码

有助于设计更健壮代码的特定API函数

这些都将在本文中讨论,并提供一些关于用户实现诊断的想法。

配置检查

Nucleus SE的设计非常便于用户配置,因此可以对其进行定制,以充分利用可用资源。这种可配置性是一个挑战,因为选项的数量以及它们之间的相互依赖性非常大。正如前面的许多文章中所描述的,Nucleus SE的大多数用户配置都是通过在nuse_config.h文件中设置#define常量来执行的。

为了帮助识别配置错误,包含了一个文件–nuse_config_check.h–即通过一个#include into nuse_config.c),该文件对#define符号执行多项一致性检查。以下是此文件的摘录:

/*** Tasks and task control ***/

#if NUSE_TASK_NUMBER < 1 || NUSE_TASK_NUMBER > 16

    #error NUSE: invalid number of tasks – must be 1-16

#endif

#if NUSE_TASK_RELINQUISH && (NUSE_SCHEDULER_TYPE ==
NUSE_PRIORITY_SCHEDULER)

    #error NUSE: NUSE_Task_Relinquish() selected – not valid with

                                          
priority scheduler

#endif

#if NUSE_TASK_RESUME && !NUSE_SUSPEND_ENABLE

    #error NUSE: NUSE_Task_Resume() selected  – task
suspend not

                                          
enabled

#endif

#if NUSE_TASK_SUSPEND && !NUSE_SUSPEND_ENABLE

    #error NUSE: NUSE_Task_Suspend() selected  – task
suspend not

                   
                       enabled

#endif

#if NUSE_INITIAL_TASK_STATE_SUPPORT && !NUSE_SUSPEND_ENABLE

    #error NUSE: Initial task state enabled – task suspend not

                                          
enabled

#endif

/*** Partition pools ***/

#if NUSE_PARTITION_POOL_NUMBER > 16

    #error NUSE: invalid number of partition pools – must be 0-16

#endif

#if NUSE_PARTITION_POOL_NUMBER == 0

    #if NUSE_PARTITION_ALLOCATE

        #error NUSE: NUSE_Partition_Allocate()
enabled – no

                       
        partition pools configured

    #endif

    #if NUSE_PARTITION_DEALLOCATE

        #error NUSE:
NUSE_Partition_Deallocate() enabled – no

                               
partition pools configured

    #endif

    #if NUSE_PARTITION_POOL_INFORMATION

        #error NUSE:
NUSE_Partition_Pool_Information() enabled –

                               
no partition pools configured

    #endif

#endif

执行的检查包括:

验证是否至少配置了一个但不超过16个任务

确认所选API函数与所选调度程序或其他选项不一致

验证是否指定了不超过16个其他内核对象的实例

确认没有为根本没有实例化的对象选择API函数

确保在未启用信号和系统时间的API函数时未选择这些功能

验证选定的计划程序类型和相关选项

在所有情况下,检测到错误都会导致编译错误语句。这通常会导致编译被指定的消息终止。

此文件不会使创建不合逻辑的配置成为不可能,但会使其变得极不可能。

API参数检查

与Nucleus RTOS一样,Nucleus SE还可以选择包含代码,以便在运行时验证API函数调用参数。通常这只会在最初的调试和测试中使用,因为在生产代码中内存和运行时开销是不需要的。

通过将NUSE_config.h中的NUSE_API_Parameter_checking设置为TRUE来启用参数检查。这样就可以编译所需的附加代码。下面是一个API函数的参数检查示例:

STATUS NUSE_Mailbox_Send(NUSE_MAILBOX
mailbox, ADDR *message,

                          
U8 suspend)

{

      STATUS return_value;

      #if NUSE_API_PARAMETER_CHECKING

         if (mailbox >=
NUSE_MAILBOX_NUMBER)

         {

              
return NUSE_INVALID_MAILBOX;

         }

         if (message == NULL)

         {

              
return NUSE_INVALID_POINTER;

         }

         #if NUSE_BLOCKING_ENABLE

            if ((suspend
!= NUSE_NO_SUSPEND) &&

                 
(suspend != NUSE_SUSPEND))

            {

                 
return NUSE_INVALID_SUSPEND;

            }

            #else

              
if (suspend != NUSE_NO_SUSPEND)

              
{

                    
return NUSE_INVALID_SUSPEND;

      
        }

            #endif

      #endif

此参数检查可能导致从API函数调用返回错误代码。这些都是NUSE_INVALID_xxx形式的负值(例如NUSE_INVALID_POINTER)–NUSE_codes.h中包含一整套定义。

可以包含额外的应用程序代码(可能是有条件地编译)来处理这些错误值,但是最好使用现代嵌入式调试器的数据监视工具来检测它们。

参数检查会导致内存开销(额外的代码)和运行时性能,因此它的使用有一定的侵入性。由于开发人员可以使用Nucleus SE的完整源代码,如果需要绝对精度,则可以在生产代码上“手动”进行检查和调试。

任务堆栈检查

只要Run-to-Completion调度器不在使用,Nucleus SE就有一个可用的任务堆栈检查工具,它与Nucleus RTOS中提供的类似,并提供剩余堆栈空间的指示。这个API调用–NUSE_Task_Check_Stack()–在上一篇文章中有详细描述。本文后面的“用户诊断”部分将讨论堆栈错误检查的一些想法。

版本信息

Nucleus RTOS和Nucleus SE有一个API函数,它只返回关于内核的版本/版本信息。

Nucleus
RTOS API Call

Service call prototype:

CHAR *NU_Release_Information(VOID);

Parameters:

None

Returns:

Pointer to NULL-terminated version string

Nucleus
SE API Call

This API call supports the key functionality of the Nucleus RTOS
API.

Service call prototype:

char *NUSE_Release_Information(void);

Parameters:

None

Returns:

Pointer to NULL-terminated version string

发布信息的Nucleus SE实现

这个API调用的实现几乎是微不足道的。返回一个指向字符串常量NUSE_Release_Info的指针,该常量在NUSE_globals.c中声明并初始化。

该字符串的形式为Nucleus SE–Xyymmdd,其中:

X是释放状态:A=α;B=β;R=释放

yy是发布的年份

mm是释放月份

dd是释放日

与Nucleus RTOS的兼容性

Nucleus RTOS包括一个用于维护历史日志的可选工具。内核记录各种系统活动的细节。提供API函数使应用程序能够:

启用/禁用历史保存

做历史记录

检索历史记录条目

Nucleus SE不支持此功能。

Nucleus RTOS还包括一些错误管理宏,这些宏执行断言,并提供一种调用用户定义致命错误函数的方法。这些是有条件地包含在OS构建中的。Nucleus SE不支持此类设施。

用户诊断

到目前为止,在本文中,我们已经了解了Nucleus SE本身提供的诊断和错误检查工具。现在是一个很好的机会来考虑如何使用内核提供的工具和/或应用我们对其内部结构和实现的知识来实现用户定义或面向应用程序的诊断。

特定于应用程序的诊断

几乎任何应用程序都可以添加额外的代码来在运行时检查其自身的完整性。使用多任务内核,让一个特定的任务来完成这项工作是非常方便和直接的。显然,对于应用程序非常特殊的诊断不在本系列文章的范围内,但是我们可以考虑一些广泛的想法。

内存检查

内存的正确操作显然对任何基于处理器的系统的完整性至关重要。同样明显的是,灾难性的故障会阻止任何软件的运行,更不用说诊断了。但是有些情况下会发生一定程度的失败,这是一个主要的问题,但并不能完全阻止代码的执行。测试内存是一个相当复杂的主题,这远远超出了本文的范围,所以我只能给出一些一般性的想法。

在RAM中,最常见的两种故障是:“卡住的位”—一个位的值为零或一,无法更改;另一个是“串扰”,相邻的位相互干扰。它们都可以通过依次向每个RAM位置写入和读回适当的测试模式来进行测试。有些测试实际上只能在启动时执行,甚至在建立堆栈之前;例如,“移动1”测试,即内存中的每个位都设置为1,并且每隔一位进行检查以确保其为零。其他逐字节模式测试可以动态执行,只要确保在RAM位置损坏时不会发生上下文切换。使用Nucleus SE critical部分来定义NUSE_CS_Enter()和NUSE_CS_Exit()宏,这两个宏是在NUSE_types.h中定义的,使用这些宏是直接和可移植的。

各种类型的ROM也会偶尔出现故障,但软件所能做的检查是有限的。生成代码时生成的校验和将很有用。这可以在启动时检查,也可以在运行时检查。

内存寻址逻辑故障会影响ROM和RAM。可以设计一个专门针对这一点的测试,但它最有可能出现在上述其他测试中。

外围设备检查

在CPU之外,外围电路可能会出现故障。当然,这将有很大的不同,从一个系统到另一个,但这是非常常见的设备有一些手段来验证其完整性与诊断软件。例如,一条通信线路可能具有回送模式,由此写入的任何数据都会立即返回。

看门狗服务

嵌入式系统设计者通常包括一个“看门狗”电路。这是一种外围设备,它可以中断CPU并期望得到迅速的响应,或者(更好)需要由软件启动的周期性访问。在这两种情况下,看门狗“咬人”的常见结果是系统重置。

在多任务环境中有效地使用看门狗是一项挑战。只需从一个任务中对其进行维护,就可以确认此特定任务正在运行。解决这一问题的一种方法是实现一个“主管任务”—本文后面将介绍这方面的一个示例。

堆栈溢出检查

除非您选择Run to Completion scheduler,否则Nucleus SE应用程序将为每个任务包含一个堆栈。这些堆栈的完整性是至关重要的,但是RAM可能是有限的,因此获得最佳大小是至关重要的。静态地预测每个任务的堆栈需求是可能的,但非常困难,它需要有足够的容量来满足最嵌套的函数调用和最需要堆栈的中断服务例程的需求。一种更简单的方法是执行详尽的运行时测试。

堆栈验证大致有两种方法。如果使用了一个复杂的嵌入式软件调试器,则可以监视堆栈边界,并检测到任何越界行为。Nucleus SE堆栈的位置和大小可以通过ROM中的全局数据结构轻松访问:NUSE_Task_Stack_Base[]和NUSE_Task_Stack_size[]。

另一种方法是执行运行时测试。通常的方法是在每个堆栈的末尾添加“保护字”–通常这些是每个堆栈数据区域中的第一个位置。这些字被初始化为可识别的非零值。然后,诊断例行程序/任务检查它们是否已更改并采取适当的措施。保护字的过度写入并不意味着堆栈实际上已经溢出,而是表示堆栈即将溢出;因此,软件可能会继续执行足够长的时间来采取纠正措施或警告用户。

监督任务

尽管Nucleus SE不保留16个任务中的任何一个供自己使用,但是用户可以选择将一个任务专用于诊断。这可能是一个低优先级的任务,它只利用任何“空闲”的CPU时间;也可能是一个高优先级的任务,偶尔会运行很短的时间,从而确保总是定期执行诊断。

下面是一个示例的功能:

主管任务的信号标志用于监视系统中六个关键任务的运行。这些任务都使用一个特定的标志(位0到位5),并且需要定期设置它。主管任务清除所有标志,然后将自身挂起一段时间。当它恢复时,它希望通过设置适当的标志来“签入”所有六个任务;它寻找与值b00111111(来自nuse_binary.h)的完全匹配。如果满足此条件,它将清除标志并再次挂起。如果没有,它将调用关键错误处理例程,例如,该例程可能执行系统重置。

另一种实现可能使用了事件标志组。如果在应用程序的其他地方没有使用信号(因为所有任务都会产生RAM开销),如果将事件标志用于其他目的,则更是如此。

跟踪和分析

尽管许多现代嵌入式软件调试器都是可定制的,并且可以使其具有“实时操作系统意识”,但调试多线程应用程序仍然具有挑战性。一种广泛使用的方法是执行后分析(post-execution profiling),其中(RTOS)代码被检测,以便对其操作的详细审计进行回顾性分析。通常,实施此类设施涉及两个部分:

附加代码被添加到RTOS(即,它被“检测”)以记录活动。通常,这将被包含在预处理器指令中,以便于条件编译。当发生重要事件(如API调用或上下文切换)时,此代码将存储一些字节的信息。这些信息应该是:

–当前地址(PC)。

–当前任务ID(索引)。

任何其他相关对象的索引。

–指示所执行操作的代码。

专门用于将配置文件信息的缓冲区清空到外部存储器(通常是主机)的任务。

分析这些捕获的数据也需要一些工作,但这可能与使用Excel电子表格一样简单。

RTOS诊断和错误检查的更多相关文章

  1. AIDE支持实时错误检查、代码重构、代码智能导航、生成APK

    AIDE是一个Android Java集成开发环境,可以在Android系统内进行Android软件和游戏的开发.它不仅仅是一个编辑器,而是支持编写-编译-调试运行整个周期,开发人员可以在Androi ...

  2. Python Cookbook(第3版)中文版:15.21 诊断分段错误

    15.21 诊断分段错误¶ 问题¶ 解释器因为某个分段错误.总线错误.访问越界或其他致命错误而突然间奔溃. 你想获得Python堆栈信息,从而找出在发生错误的时候你的程序运行点. 解决方案¶ faul ...

  3. Linux:服务器/客户端API调用错误检查

    昨天和今天上午,我分别实现简单的服务器和客户端,运行之后表示没问题,一切正常.但是这还是有问题的,最大的一个就是没有错误检查.现在我们来加上错误检查: 服务器的代码: #include <std ...

  4. How to do error checking in CUDA(如何在CUDA里做错误检查)

    https://codeyarns.com/2011/03/02/how-to-do-error-checking-in-cuda/ Error checks in CUDA code can hel ...

  5. NODEjs常见错误检查

    一.没有添加对uncaughtException异常的捕捉处理,最起码也要在其中写个日志记录错误,然后可以调用 process.exit(1); 退出进程. 二.处理函数的回调函数检查,经常忘记在回调 ...

  6. sublime text 2 php 语法错误检查

    使用sublime text 2 编写php程序的时候,保存代码的时候,直接检查出语法错误,有利于提高效率. 1.安装sublime text 2 package menu : preferences ...

  7. 错误检查roswtf

    准备 在你开始本教程之前请确保roscore没在运行. 安装检查 roswtf 可以检查你的ROS系统并尝试发现问题,我们来试看: $ roscd $ roswtf 你应该会看到(各种详细的输出信息) ...

  8. 如何利用C# Roslyn编译器写一个简单的代码提示/错误检查?

    OK, 废话不多说,这些天在写C#代码时突然对于IDE提示有了一些想法,之前也有了解过,不过并没有深入. 先看个截图: 一段再简单不过的代码了,大家注意看到 count 字段下面的绿色波浪线了吗,我们 ...

  9. (二)如何利用C# Roslyn编译器写一个简单的代码提示/错误检查?

    上一篇我们讲了如何建立一个简单的Roslyn分析项目如分析检查我们的代码. 今天我们主要介绍各个项目中具体的作用以及可视化分析工具. 还是这种截图,可以看到解决方案下一共有三个项目. Analyzer ...

随机推荐

  1. hdu4932 小贪心

    题意:      给了一些处在x轴上的点,要求我们用长度相等的线段覆盖所有点,线段和线段之间不能重叠,问线段最长可以使多长. 思路:       一开始一直在想二分,哎!感觉这个题目很容易就往二分上去 ...

  2. windows-CODE注入(远程线程注入)

    远程线程注入(先简单说,下面会详细说)今天整理下代码注入(远程线程注入),所谓代码注入,可以简单的理解为是在指定内进程里申请一块内存,然后把我们自己的执行代码和一些变量拷贝进去(通常是以启线程的方式) ...

  3. Python练习2-基本聊天程序-虚拟茶会话

    基本聊天程序 先来个基本的测试例子: Main.py from asyncore import dispatcher import socket,asyncore PORT = 11223 class ...

  4. linux 查看运行java所在目录

    通过ps及top命令查看进程信息时,只能查到相对路径,查不到的进程的详细信息 需要查看pos_service.jar的绝对路径(在哪里目录下)  使用:ll /proc/PID Linux在启动一个进 ...

  5. 从刚毕业的5K测试到20K测试大佬,与薪资相匹配的永远是实力!

    有个话题"软件测试的工资高还是开发者的工资高?"软件测试和软件开发门槛有差异,在职业起步阶段收入也会有一定的差异,这算是行业内公开的秘密.但随着工作年限的增加,经验的逐步积累,软件 ...

  6. MFC Object 与 Windows Object

    MFC Object 和 Windows Object的含义 Window Object(Window对象)是Win32下用句柄表示的Windows操作系统对象.MFC Object(MFC对象)是C ...

  7. 黄衫女子,黄衫好.png

    正想着团队项目中数据该如何解析,就收到了来自软工课程组的一件小黄衫,真是意外之喜.详问其来源,竟是因结对项目做的"较好"而来,顿感受之有愧. 结对项目是两人对文件系统的一个小模拟, ...

  8. C++知识点案例 笔记-4

    1.纯虚函数 2.抽象类 3.内部类 4.运算符重载 5.类的函数重载 6.友元的函数重载 1.纯虚函数 ==纯虚函数== //有时基类中无法给出函数的具体体现,定义纯虚函数可以为派生函数保留一个函数 ...

  9. Centos 7 进入单用户模式更改root密码方法

    进入单用户模式的方法 方法一: 1.开机进入grub菜单的时候上下选择,按e编辑. 到linux16所在行的最后面. ro 只读文件系统 biosdevname=0 戴尔的服务器需要设置 net.if ...

  10. IDEA Git 操作常见错误处理

    使用 IDEA 的 git 进行操作时报错 更新报错 Git Pull Failed: refusing to merge unrelated histories 提交报错 Push rejected ...