程序以状态码255退出:C++主程序与Ada

3
我有一组使用Ada编写的单线程C++主程序。这些程序使用Atego (Rational) Apex Duo构建,并针对32位RHEL 6.3 Linux系统进行开发。该执行系统是我开发的一个类系统,其中包括套接字、状态机和计时器类,是该执行系统的核心。该类系统用于构建和执行14个不同的执行系统,它们在6个不同的系统之间通过套接字通信。它们都使用相同的类系统,并根据INI文件在启动时进行配置。
这些执行系统以50或60赫兹的频率进行帧处理,其使用Linux系统时钟,通过gettimeofday函数进行操作。
struct timeval {
    time_t      tv_sec;     /* seconds */
    suseconds_t tv_usec;    /* microseconds */
};

同时,我们需要一个简单的非忙等算法来生成所需的调度程序。

我目前面临的问题是这些execs(可执行文件)会(看起来)随机失败。故障似乎表现为它们突然停止帧处理。我已经将所有运行时C++过程封装在“try{}catch(...){}”中,并且没有捕获到任何异常。同样,Ada例程也受到不被触发的异常处理程序的保护。

该exec通常会在运行30分钟到一小时以上后才会出现故障。没有任何内存增长的迹象(使用系统监视器)。我已经将Atego Rational图形调试器附加到已经运行的exec上,但没有用。当最终失败时,调用堆栈中没有任何内容,调试器日志中唯一的指示是应用程序“以状态255退出”。

我担心系统中的某个(Linux)系统例程或驱动程序正在调用Exit。显然有些东西正在调用exit!

有人有任何想法如何进一步调试此问题吗?


上次我遇到这样的问题时,我正在使用一个带有保留/释放机制的库,并且我错误地释放了一个常量。它逐渐降低了保留计数,直到被释放,在运行几个小时后发生了错误。我提到这一点是因为你提出的问题似乎没有足够的信息来尝试回答,所以这是我能给出的最好的答案。 - Dave
执行者是否对称,还是各不相同?它们全部失败还是只有一部分失败? - user1818839
你使用C++计时函数有特别的原因吗?如果你的C++主程序是一个测试类型的程序,那么编写一个类似的Ada程序并尝试一下是否会太麻烦呢?(为了排除代码段的影响;如果问题仍然存在,则很可能是Ada方面的问题,如果问题消失,则是C++方面的问题。) - Shark8
你可以尝试使用某些东西来包装exit(),以记录堆栈跟踪。参考链接 - Simon Wright
Simon,谢谢...听起来是个好建议,因为我目前没有任何迹象。我已经决定尝试使用atexit()来达到同样的目的。 - raetza
显示剩余3条评论
3个回答

2

这可能不是一个完整的答案,但对于评论来说范围太广了...

所以失败发生在每台6台机器上的单个可执行文件中; 负责在网络上共享数据的可执行文件; 对吗?而“本地”可执行文件似乎是可靠的...或者这6个故障的文件与6个系统并不是那么清晰的映射关系吗?

故障是否与网络负载有关,例如延迟是否超过您(电视或交流电源)的帧速率?通过堵塞网络使其更快地失败可以简化测试...

当Linux网络时钟倒流时,我的系统崩溃了... C++组件出现了故障,因此当dt变为负数时没有易于约束的错误,但故障线路下方出现了荒谬的“4e9微秒超时”...

听起来,Ada的任务处理功能和分布式系统附录非常适合这种应用程序,但在这个阶段进行这种级别的设计更改可能不合适。


Brian,6个执行失败的执行文件映射到6台机器...它们是负责I/O(UDP、多播、MIL-STD-1553)的执行文件。这些执行文件完全是单线程的,并且执行时就像通过RTOS运行它们一样(它们从PPC上的VxWorks移植到x86-86上的Linux)。我选择使用C++主程序,因为对我来说在开发涉及大量套接字的项目时,使用C++比Ada更容易。 - raetza
我现在相信问题是被Ada RTS困住了,它通过恐慌生成了exit()调用。 我通过在主程序中使用atexit()陷入exit()并在其上设置断点来通过调用栈了解到这一点。 但是,我仍在寻找问题的原因...是什么错误导致Ada RTS调用exit()? 我的感觉是在Ada代码中的某个地方...或者是类似于堆栈越界之类的奇怪问题。 - raetza
惊慌退出;这听起来不像是Ada RTS会做的事情。除非它引发异常以供主子程序处理,但(不是Ada的)主程序无法识别该异常。所有的Ada代码是否都包含在“begin ... do stuff ... exception ... print stuff ... end”层中?或者,为一个失败的任务创建一个Ada主程序是否太难了? - user1818839
关于恐慌和退出的前一个评论的补充说明:只要标准运行时检查已开启,就不会出现这种情况。是否可能执行文件是在没有这些检查的情况下构建的? - user1818839
Brian,通过Atego技术支持,我们已经确定Ada RTS包含一个名为panic_exit_application_no_ct的符号。这通常是由任务死锁引起的,但他们说它也可能来自其他原因(可能是我们的情况)。在调试器调用堆栈中出现了对exit()的调用,因此我们知道exit()是从Ada RTS中调用的...我们还不知道原因。 - raetza
显示剩余3条评论

0

现在看来,Ada RTS 对 C++ 主程序不是很“满意”。虽然并非所有问题都得到了解决,但已经修复。我们从 C++ 主程序改为 Ada 主程序,这是一个简单的更改,现在 Ada 导入了一堆 C++,而不是相反。它不像 C++ 主程序那样完美,但我想功能比漂亮更重要。

未解答的问题是为什么它一开始就死了?而且为什么只有一些执行文件会死掉,而其他执行文件却可以一直运行下去?我们怀疑这与某些东西越界有关,最终导致应用程序在调用 Ada 中的例程时需要做更多的事情,它就越快死亡。这让我们相信栈被破坏了,但为什么只有 C++ 主程序会出现这种情况呢?

无论如何,它现在使用 Ada 主程序可以工作,而工作是最重要的要求...所以我们称之为“修复”。


0

也许它可以给你一些进一步的指导:

如果你尝试从主函数返回双精度数,可能会发生这样的情况。 参见:

double main ()
{
    return 0.0;
}
$ cc double.c
double.c: 在函数 'main' 中:
double.c:2: 警告: 'main' 的返回类型不是 'int'
$ ./a.out
$ echo $?
255
$

如果在 POSIX 操作系统下尝试从 main() 函数返回 double 类型,调用进程几乎总会看到 255。


Brian,好问题。实际上,14个高管中只有6个表现出这种行为。这6个都与I/O相关联。I/O在盒子(独立系统)之间进行,包括通过PC中的NIC的UDP和Multicast以太网套接字数据以及通过PC中的1553卡的MIL-STD-1553数据。其余的8个高管与其他高管一起运行,只有内部(共享内存)数据交换。这8个似乎永远不会失败地运行。此外,所有高管都不同...他们只是共同拥有我为套接字I/O、INI读取、定时和状态机执行开发的类系统。 - raetza
Shark8,这段代码在单播和组播套接字方面有很多I/O。为了将类系统应用于实现,我使用C++作为主要语言会更容易些。 - raetza

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接