主循环不会正常退出

时间:2013-08-25 17:27:02

标签: c terminal atexit

我创建了这个函数,它充当基于终端的应用程序的主菜单:

bool wizard_run() {
   char *command = NULL;
   bool repeat = false;
   bookmark:

   terminal_prepare();
   terminal_message(MESSAGE_INTRODUCTION);

   loop: /* repeat until a valid command */ {
      free(command); /* free any previous command */
      command = terminal_command(PROMPT_COMMAND, COMMAND_LENGTH, repeat);

      if (!strcmp(command, COMMAND_ENCRYPT)) wizard_encrypt();
      else if (!strcmp(command, COMMAND_DECRYPT)) wizard_decrypt();
      else if (!strcmp(command, COMMAND_CONCEAL)) wizard_conceal();
      else if (!strcmp(command, COMMAND_REVEAL)) wizard_reveal();
      else if (!strcmp(command, COMMAND_ERASE)) wizard_erase();
      else if (!strcmp(command, COMMAND_GENERATE)) wizard_generate();
      else if (!strcmp(command, COMMAND_NAVIGATE)) directory_navigate(RDS_HOME)
      else if (!strcmp(command, COMMAND_SESSION)) wizard_session();
      else if (!strcmp(command, COMMAND_SAFEMODE)) wizard_safemode();
      else if (!strcmp(command, COMMAND_HELP)) wizard_help(HELP_MAINMENU)
      else if (!strcmp(command, COMMAND_EXIT)) {free(command); return false;}
      else {repeat = true; goto loop;}
   }

   free(command); /* free last command */
   return true;
}

所有大写的值都是#defined个常量,所有...(...)都是除wizard_help(...)directory_navigate(...)之外的函数,这些函数是宏(这就是为什么没有分号结束这些行的原因)。< / p>

这是应用程序的主要功能:

void main() {
   // initialize any Components needed
   if (!directory_rdsload()) return;
   packager_reset();

   // show the Splash Screen
   SPLASH();

   // continuously execute the Main Thread
   while (wizard_run()); /* execution loop */

   // perform any Clean-UP needed before exit
   reset();
   encryption_reset();
   directory_reset(is_safemode);
}

此处,只有SPLASH()是一个宏。

所有布尔值(即truefalse)都是预定义的无符号字符值,而booltypedef unsigned char bool;

当用户输入wizard_run()(COMMAND_EXIT的当前值),执行exit然后正常终止应用程序时,它的正常行为是退出reset(); encryption_reset(); directory_reset(is_safemode);循环。相反,当我第一次键入exit时,它会重新显示菜单,当我第二次键入exit时,它会终止,并显示以下错误:

application: cxa_atexit.c:99: __new_exitfn: Assertion `l != ((void *)0)' failed.
Aborted (core dumped)

当程序在gdb下运行时,我收到此错误:

application: cxa_atexit.c:99: __new_exitfn: Assertion `l != ((void *)0)' failed.

Program received signal SIGABRT, Aborted.
0xb7fdd424 in __kernel_vsyscall ()

main()之外没有其他功能曾调用wizard_run(),因此这不是重新显示菜单而不是退出的原因。有什么想法吗?

提前致谢!!! :d

1 个答案:

答案 0 :(得分:0)

好的,最终我发现了问题!它位于SPLASH()内。这是一个宏定义为:

#define SPLASH() { \
   if (!vfork()) execlp("/bin/splash", "/bin/splash", NULL); \
   else wait(); \
}

由于我的应用程序仍处于测试阶段,我没有将splash放在目录/bin中。我从没想过这可能是个问题。但是,这里有一个问题:我使用vfork代替fork,因为我只想执行一个新程序(vfork更快,当你不需要Child时父进程的副本)。由于不存在/bin/bash,execlp没有为子进程加载新的应用程序映像。因此,我可以想象两个进程共享其图像的一部分? (look here

因此,当调用SPLASH()时,子进程将接管并再次显示主菜单。一切都很好看。但是当我调用exit时,Child正常终止并且Parent控制终端并重新显示主菜单(这就是它显示两次的原因!)。再次调用exit时,父进程'轮到终止。但是,Child进程 - 与父进程共享相同的进程映像 - 已经终止,从而改变了一些数据。一定是这个改变的数据导致退出时出错。

当我的功能清除终端并覆盖以前的消息时,我无法注意到Child进程首先显示主菜单! ;)

我对整个问题的性质感到非常兴奋。虽然我无法更好地解释它(我的术语肯定会犯一些错误),但我希望你能理解出了什么问题!感谢大家的有用评论(尤其是WhozCraig)! :d