AC源代码(编译并运行Linux Centos 6.3)有以下行:
execve(cmd, argv, envp);
Run Code Online (Sandbox Code Playgroud)
execve不返回,但我想修改代码以知道它何时完成。所以我这样做:
if (child = fork()) {
waitpid(child, NULL, 0);
/*now I know execve is finished*/
exit(0);
}
execve(cmd, argv, envp);
Run Code Online (Sandbox Code Playgroud)
当我这样做时,生成的程序在 99% 的情况下都能正常工作,但很少会出现奇怪的错误。
以上有什么问题吗??我希望上面的代码能够像以前一样精确运行(除了慢一点)。我对么?
如果你想了解背景,修改后的代码是dash。该execve调用用于在dash找出要运行的字符串后运行一个简单的命令。当我按照上面的方式进行精确修改(等待后甚至没有运行任何东西)并在修改后的破折号下重新编译和运行程序时,大多数时候它们运行良好。然而,重新编译一个名为“biosutility”的特定内核模块给了我这个错误
cc1: error: unrecognized command line option "-mfentry"
Run Code Online (Sandbox Code Playgroud)
仔细阅读execve(2)、fork(2)和waitpid(2)的文档。execve&都很fork棘手,fork 也很难理解。我强烈建议阅读《高级 Linux 编程》(可以在网上免费获得,但你可以购买纸质书),其中有几个章节解答了这些问题。
(不要害怕花几天时间阅读和理解这些系统调用,它们很棘手)
一些重要的观点。
每个 系统调用 都可能失败,您应该始终处理其失败,至少通过使用perror(3)显示一些错误消息并立即exit(3) -ing。
execve (2)系统调用通常永远不会返回,因为它仅在失败时返回(成功时,它不会返回,因为调用程序已被替换,因此被删除!)因此大多数对它的调用(以及类似的exec(3)函数) )通常是这样的:
if (execve(cmd, argv, envp)) { perror (cmd); exit(127); };
/* else branch cannot be reached! */
Run Code Online (Sandbox Code Playgroud)
通常在execve 失败时使用奇怪的退出代码,如 127(通常未使用,除了上面的情况),而且通常您无法执行任何其他操作。当使用(几乎总是)时,fork您经常会调用execve子进程。
fork (2)系统调用成功时返回两次(一次在父进程中,一次在子进程中)。这很难理解,请阅读我给出的参考资料。它仅在失败时返回一次。所以你总是保留 的结果fork,所以典型的代码是:
pid_t pid = fork ();
if (pid<0) { // fork has failed
perror("fork"); exit(EXIT_FAILURE);
}
else if (pid==0) { // successful fork in the child process
// very often you call execve in child, so you don't continue here.
// example code:
if (execve(cmd, argv, envp)) { perror (cmd); exit(127); };
// not reached!
};
// here pid is positive, we are in the parent and fork succeeded....
/// do something sensible, at some point you need to call waitpid and use pid
Run Code Online (Sandbox Code Playgroud)建议:在某些程序上使用strace(1)strace -f bash -c 'date; pwd' ,也许尝试研究输出。它提到了许多系统调用(2) ....
您的示例代码可能(有时)只需添加一些else类似的内容即可工作
// better code, but still wrong because of unhandled failures....
if ((child = fork())>0) {
waitpid(child, NULL, 0);
/*now I know execve is finished*/
exit(0);
}
/// missing handling of `fork` failure!
else if (!child) {
execve(cmd, argv, envp);
/// missing handling of `execve` failure
}
Run Code Online (Sandbox Code Playgroud)
但该代码仍然不正确,因为未处理故障。