poll()调用返回未被手册记载的ECHILD错误,求原因分析
poll()返回未记载的ECHILD错误的排查思路
核心原因:信号处理干扰导致errno被覆盖
ECHILD(错误码10)的常规含义是"没有子进程",但poll()本身不会直接返回这个错误。最常见的触发场景是:
- 程序注册了
SIGCHLD信号处理函数用于回收退出的子进程; poll()等待过程中,子进程退出触发SIGCHLD,导致poll()被中断(原本应返回-1且errno=EINTR);- 信号处理函数中调用了
wait()/waitpid(),若此时没有待回收的子进程(比如信号被多次触发、子进程已被回收),waitpid()会将errno设置为ECHILD; - 当你在
poll()返回-1后读取errno时,拿到的是信号处理函数修改后的ECHILD,而非poll()本身设置的EINTR。
验证与解决方法
检查信号处理逻辑
查看代码中是否存在未正确处理返回值的SIGCHLD处理函数,比如:void sigchld_handler(int sig) { // 未检查返回值的waitpid调用会修改errno waitpid(-1, NULL, WNOHANG); }这类代码在无可用子进程回收时,
waitpid()返回-1并将errno设为ECHILD。修复信号处理函数
在信号处理函数中保存和恢复errno,避免干扰主逻辑:void sigchld_handler(int sig) { int saved_errno = errno; // 循环回收所有退出的子进程,避免信号丢失 while (waitpid(-1, NULL, WNOHANG) > 0); errno = saved_errno; }处理poll的EINTR情况
即使修复了信号处理函数,poll()仍可能被信号中断,需在主逻辑中处理该情况而非直接退出:else if(rc < 0) { if (errno == EINTR) { // 被信号中断,继续等待 continue; } printf("poll error %d\n", errno); exit(1); }
其他边缘可能性
如果监听的fd是与子进程关联的管道、PTY等描述符,某些特定内核版本或系统中,可能在子进程异常退出时出现这类未文档化的poll()行为,但这种情况远不如信号处理干扰常见,优先排查信号逻辑。
内容的提问来源于stack exchange,提问作者White Owl
相关产品推荐
相关产品推荐

