我创建了这个函数,它充当基于终端的应用程序的主菜单:
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()
是一个宏。
所有布尔值(即true
,false
)都是预定义的无符号字符值,而bool
是typedef 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
答案 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