You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

子僵尸进程调用setpgid返回ESRCH而非EACCES的原因

为什么setpgid返回ESRCH而非预期的EACCES?

嘿,我来拆解下你遇到的这个问题——核心原因其实很直白:你fork出来的子进程执行的ls命令,在父进程sleep的2秒内就已经完全退出了。当父进程醒过来调用setpgid时,目标PID对应的进程已经不存在了,所以内核返回了ESRCH(找不到进程),而不是你预期的EACCES。

先理清楚手册里的错误码前提

先回顾下setpgid(2)手册里的两个错误码定义:

EACCES:尝试修改调用进程的子进程进程组ID,但该子进程已执行execve(2)(setpgid()、setpgrp())。
ESRCH:对于getpgid(),pid无匹配进程;对于setpgid(),pid既非调用进程也非其子进程。

注意EACCES的触发前提是:目标进程确实存在,只是它已经执行过exec了。而ESRCH的触发条件是内核根本找不到这个PID对应的进程——这个错误的优先级更高,只要进程不存在,就会先返回它。

你的代码里发生了什么?

你的代码逻辑是:

  1. 父进程fork出子进程,子进程立刻exec ls命令
  2. 父进程sleep 2秒,然后调用setpgid(ls_pid, ls_pid)

但ls是一个极短的命令:它只是列出当前目录的文件,完成后立即终止,整个过程耗时远不到2秒。等父进程sleep结束后,ls_pid对应的进程早就消失了,内核里已经没有这个PID的进程实体。这时候调用setpgid,内核找不到目标进程,自然返回ESRCH,根本轮不到触发EACCES的条件。

怎么验证这个结论?

你可以修改代码,让子进程exec一个不会很快退出的程序,比如sleep 10——这样父进程sleep 2秒后,子进程还在运行,这时候调用setpgid就会返回你预期的EACCES:

修改后的测试代码:

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
void print_errno() {
    if (errno == EACCES) printf("errno: EACCES\n");
    else if (errno == EPERM) printf("errno: EPERM\n");
    else if (errno == ESRCH) printf("errno: ESRCH\n");
}
#define CHECK(syscall, msg) do { \
    if ((syscall) == -1) { \
        print_errno(); \
        perror(msg); \
        _exit(1); \
    } \
} while(0)
int main () {
    int sleep_pid;
    char *sleep_argv[] = { "sleep", "10", NULL };
    CHECK(sleep_pid = fork(), "fork error");
    if (!sleep_pid) {
        CHECK(execvp(sleep_argv[0], sleep_argv), "execvp error");
    } else {
        sleep(2);
        int ret = setpgid(sleep_pid, sleep_pid);
        if (ret == -1) {
            print_errno();
            perror("setpgid error");
        } else {
            printf("setpgid success\n");
        }
        CHECK(wait(NULL), "wait error");
        printf("Finish\n");
    }
}

运行这段代码,你会看到输出errno: EACCES,完全符合手册的预期。

额外提醒

如果想测试exec后的子进程触发EACCES的场景,一定要保证在调用setpgid时,子进程还处于运行状态——像ls这种瞬间完成的命令,根本满足不了这个条件。

内容的提问来源于stack exchange,提问作者K.Miao

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:42:55