HP-UX平台FIFO上poll(2)调用立即返回的异常问题咨询
我之前也碰到过类似的跨平台poll(2)对FIFO的处理差异问题,尤其是HP-UX的表现确实和Linux、Solaris、AIX这些主流Unix-like系统不一样。先帮你梳理下问题核心、差异原因和解决思路:
问题重现与预期不符点
你提到的场景是:创建FIFO后,在没有任何写入操作的情况下调用带3秒超时的poll(2),预期返回值为0(超时),但HP-UX的行为和其他平台不一致。我把你给出的代码补全完整,方便更清晰地分析:
#include <fcntl.h> #include <poll.h> #include <signal.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> #include <errno.h> #include <inttypes.h> #include <stdio.h> int main() { const char *fifo_path = "/tmp/test_fifo"; struct pollfd pfd; int ret; // 创建FIFO,已存在则忽略错误 if (mkfifo(fifo_path, 0666) == -1 && errno != EEXIST) { perror("mkfifo failed"); return 1; } // 以只读非阻塞方式打开FIFO int fd = open(fifo_path, O_RDONLY | O_NONBLOCK); if (fd == -1) { perror("open failed"); return 1; } // 设置poll参数,监听可读事件 pfd.fd = fd; pfd.events = POLLIN; pfd.revents = 0; // 调用poll,超时3秒 ret = poll(&pfd, 1, 3000); printf("poll返回值: %d, errno: %d, revents: %d\n", ret, errno, pfd.revents); close(fd); unlink(fifo_path); return 0; }
在Linux、Solaris、AIX上,因为没有进程打开FIFO的写入端,poll(2)会等待3秒后返回0;但在HP-UX上,它会立刻返回1,同时pfd.revents会被标记为POLLHUP(挂起事件),这就是核心的行为差异。
差异背后的原因
HP-UX的poll(2)实现逻辑比较特殊:当FIFO以只读方式打开且没有任何写入端连接时,它会认为这个读取端已经处于"永久无法获取数据"的状态,所以直接触发POLLHUP事件返回,而不会等待超时。而其他系统则将这种情况视为"暂时无数据",会严格遵循超时设置,到时间后返回0。
跨平台兼容的解决方案
要让HP-UX的行为和其他平台保持一致,你需要在处理poll返回值时,额外判断POLLHUP事件,模拟出超时返回0的逻辑。修改后的核心处理代码如下:
ret = poll(&pfd, 1, 3000); if (ret == 1) { // 仅当只有POLLHUP触发,且无POLLIN事件时,模拟超时 if ((pfd.revents & POLLIN) == 0 && (pfd.revents & POLLHUP)) { ret = 0; errno = 0; printf("模拟超时返回\n"); } else { // 处理正常的可读或其他异常事件 printf("检测到可读/异常事件\n"); } } else if (ret == 0) { printf("正常超时\n"); } else { perror("poll调用出错"); }
另外,如果你需要更省心的跨平台兼容,也可以考虑用select(2)替代poll(2)——select在各平台上对FIFO的超时处理逻辑更统一,都是在无写入端时等待到超时返回0。
验证建议
你可以在HP-UX上分别运行原始代码和修改后的代码,对比返回值确认效果。需要注意的是:如果后续有进程打开FIFO的写入端,POLLHUP会在写入端关闭时触发,这时候属于正常的连接断开,要和"初始无写入端"的情况区分开,避免误判。
内容的提问来源于stack exchange,提问作者Byoungchan Lee

