使用 waitpid 和 WNOHANG 区分进程状态
Differentiate processes states using waitpid and WNOHANG
在构建 shell 程序时,我遇到了识别进程状态的问题。我面临的问题的描述是我有一个子进程列表,我正在尝试使用 waitpid
和 WNOHANG
来弄清楚它们的状态。我想区分 3 种状态:TERMINATED
、RUNNING
和 SUSPENDED
。 (如以下代码中所定义)
我希望将进程状态更改为以上三种之一,但是现在此函数使 运行 进程状态变为 terminated
,并且此函数也无法识别挂起的进程。
我想知道我做错了什么以及应该如何编写函数updateProcessList
来实现它?
#define TERMINATED -1
#define RUNNING 1
#define SUSPENDED 0
typedef struct process{
cmdLine* cmd; /* the parsed command line*/
pid_t pid; /* the process id that is running the command*/
int status; /* status of the process: RUNNING/SUSPENDED/TERMINATED */
struct process *next; /* next process in chain */
} process;
void updateProcessList(process **process_list) {
process *p = *process_list;
int code = 0, status = 0,pidd = 0;
while (p) {
pidd = p->pid;
code = waitpid(pidd, &status, WNOHANG);
if (code == -1) { /* child terminated*/
p->status = TERMINATED;
} else if(WIFEXITED(status)){
p->status = TERMINATED;
}else if(WIFSTOPPED(status)){
p->status = SUSPENDED;
}
p = p->next;
}
}
来自 man 2 waitpid
:
RETURN VALUE
waitpid(): on success, returns the process ID of the child whose state has changed;
if WNOHANG was specified and one or more child(ren) specified by pid exist, but have
not yet changed state, then 0 is returned. On error, -1 is returned.
您应该检查 0
的 return 值...并修复其余的检查。
code = waitpid(ppid, &status, WNOHANG | WUNTRACED | WCONTINUED);
if (code == -1) {
// Handle error somehow...
// This doesn't necessarily mean that the child was terminated!
// See manual page section "ERRORS".
if (errno == ECHILD) {
// Child was already terminated by something else.
p->status = TERMINATED;
} else {
perror("waitpid failed");
}
} else if (code == 0) {
// Child still in previous state.
// Do nothing.
} else if (WIFEXITED(status)) {
// Child exited.
p->status = TERMINATED;
} else if (WIFSIGNALED(status)) {
// Child killed by a signal.
p->status = TERMINATED;
} else if (WIFSTOPPED(status)) {
// Child stopped.
p->status = SUSPENDED;
} else if (WIFCONTINUED(status)) {
// This branch seems unnecessary, you should already know this
// since you are the one that should kill(pid, SIGCONT) to make the
// children continue.
p->status = RUNNING;
} else {
// This should never happen!
abort();
}
另请注意:
- 我在标志中添加
WUNTRACED
和 WCONTINUED
:WIFSTOPPED()
不会发生,除非您使用 ptrace()
跟踪 child 或者您使用了WUNTRACED
标志,并且 WIFCONTINUED()
不会发生,除非使用 WCONTINUED
。
code
和 ppid
变量应该是 pid_t
,而不是 int
(ppid
变量似乎也不需要)。
无论如何,请考虑为 SIGCHLD
添加一个信号处理程序并在那里更新 children 状态。对于 terminates/stops/resuems 中的每一个 child,您的程序将收到一个 SIGCHLD
。它更简单也更快(不需要在每个 child 进程上连续调用 waitpid()
)。
在构建 shell 程序时,我遇到了识别进程状态的问题。我面临的问题的描述是我有一个子进程列表,我正在尝试使用 waitpid
和 WNOHANG
来弄清楚它们的状态。我想区分 3 种状态:TERMINATED
、RUNNING
和 SUSPENDED
。 (如以下代码中所定义)
我希望将进程状态更改为以上三种之一,但是现在此函数使 运行 进程状态变为 terminated
,并且此函数也无法识别挂起的进程。
我想知道我做错了什么以及应该如何编写函数updateProcessList
来实现它?
#define TERMINATED -1
#define RUNNING 1
#define SUSPENDED 0
typedef struct process{
cmdLine* cmd; /* the parsed command line*/
pid_t pid; /* the process id that is running the command*/
int status; /* status of the process: RUNNING/SUSPENDED/TERMINATED */
struct process *next; /* next process in chain */
} process;
void updateProcessList(process **process_list) {
process *p = *process_list;
int code = 0, status = 0,pidd = 0;
while (p) {
pidd = p->pid;
code = waitpid(pidd, &status, WNOHANG);
if (code == -1) { /* child terminated*/
p->status = TERMINATED;
} else if(WIFEXITED(status)){
p->status = TERMINATED;
}else if(WIFSTOPPED(status)){
p->status = SUSPENDED;
}
p = p->next;
}
}
来自 man 2 waitpid
:
RETURN VALUE waitpid(): on success, returns the process ID of the child whose state has changed; if WNOHANG was specified and one or more child(ren) specified by pid exist, but have not yet changed state, then 0 is returned. On error, -1 is returned.
您应该检查 0
的 return 值...并修复其余的检查。
code = waitpid(ppid, &status, WNOHANG | WUNTRACED | WCONTINUED);
if (code == -1) {
// Handle error somehow...
// This doesn't necessarily mean that the child was terminated!
// See manual page section "ERRORS".
if (errno == ECHILD) {
// Child was already terminated by something else.
p->status = TERMINATED;
} else {
perror("waitpid failed");
}
} else if (code == 0) {
// Child still in previous state.
// Do nothing.
} else if (WIFEXITED(status)) {
// Child exited.
p->status = TERMINATED;
} else if (WIFSIGNALED(status)) {
// Child killed by a signal.
p->status = TERMINATED;
} else if (WIFSTOPPED(status)) {
// Child stopped.
p->status = SUSPENDED;
} else if (WIFCONTINUED(status)) {
// This branch seems unnecessary, you should already know this
// since you are the one that should kill(pid, SIGCONT) to make the
// children continue.
p->status = RUNNING;
} else {
// This should never happen!
abort();
}
另请注意:
- 我在标志中添加
WUNTRACED
和WCONTINUED
:WIFSTOPPED()
不会发生,除非您使用ptrace()
跟踪 child 或者您使用了WUNTRACED
标志,并且WIFCONTINUED()
不会发生,除非使用WCONTINUED
。 code
和ppid
变量应该是pid_t
,而不是int
(ppid
变量似乎也不需要)。
无论如何,请考虑为 SIGCHLD
添加一个信号处理程序并在那里更新 children 状态。对于 terminates/stops/resuems 中的每一个 child,您的程序将收到一个 SIGCHLD
。它更简单也更快(不需要在每个 child 进程上连续调用 waitpid()
)。