我目前正在针对某些故障注入测试我们的软件。现在我在 D 状态或 Z 状态下运行 systemd 守护进程时遇到问题。任何帮助将不胜感激!
创建“D”状态进程:
sudo cat $(mount | awk '$3 == "/" { print $1 }') > /dev/null
# Then run "top" command,
# Sometimes, you'll see "cat" process in "D" state, most of the time in "R" state
要创建“Z”状态进程,请使用以下 C 代码 (zombie.c) 创建程序:
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main ()
{
pid_t child_pid;
child_pid = fork ();
if (child_pid > 0) {
sleep (60);
}
else {
exit (0);
}
return 0;
}
然后
gcc -o zombie zombie.c
./zombie
虽然另一个答案确实给出了创建D状态进程的方法,但它并不可靠,并且进程会重复进入和退出D状态。在 Linux 上,更可靠的方法是使用
vfork
(有关其工作原理的更多信息,请参阅本文)。举个例子:
#include <unistd.h>
__attribute__((noinline)) static void run_child(void)
{
pause();
_exit(0);
}
int main(void)
{
pid_t pid = vfork();
if (pid == 0) {
run_child();
} else if (pid < 0) {
return 1;
}
return 0;
}
__attribute__((noinline))
是一个好主意,可以确保子级使用的堆栈空间与父级使用的堆栈空间分开。通过防止内联,我们确保函数在入口处创建一个不同的堆栈帧,并且在 vfork()e
d 子级的上下文中,这意味着任何堆栈操作都整齐地发生在单独的帧中,而不是在父级的堆栈帧中。如果没有它,编译器可能会执行优化,从而导致父级和子级之间的数据交错,这可能会导致父级恢复时堆栈损坏。
然后将进入 D 状态,直到发送终端信号:
% cc -o dstate dstate.c
% ./dstate & sleep 0.1; ps -o pid,state,cmd -p "$!"
[1] 780629
PID S CMD
780629 D ./dstate
% kill "$!"
[1] + terminated ./dstate
(Philippe 的另一个答案已经为 Z 状态过程提供了一个很好的解决方案,所以我将再次省略回答该部分。)