pipe2(...) vs pipe() + fcntl(...),为什么不同?
pipe2(...) vs pipe() + fcntl(...), why different?
我正在尝试构建一个可再发行的二进制文件以放置在只有 glibc 2.3 的旧 NAS 上。所以 pipe2()
在那台机器上不可用,但我要构建的代码有以下行:
if (pipe2(info_pipe, O_CLOEXEC | O_NONBLOCK) < 0)
goto info_pipe_err;
我的理解是 pipe2()
存在的原因是通过在打开时取 O_CLOEXEC | O_NONBLOCK
与分两步进行来避免竞争条件。但是我正在查看的情况下没有线程,所以我想我可以替换为:
if (pipe(info_pipe) < 0)
goto info_pipe_err;
int direction; // 0=READ, 1=WRITE
for (direction = 0; direction < 2; ++direction) {
int oldflags;
oldflags = fcntl(info_pipe[direction], F_GETFL);
if (oldflags < 0)
goto info_pipe_err;
if (fcntl(info_pipe[direction],
F_SETFL, oldflags | O_NONBLOCK | O_CLOEXEC) < 0)
goto info_pipe_err;
}
但它似乎不可互换,因为代码不起作用。为什么这不等价?
(回答我自己的问题因为我想通了,只是在这里发帖以供后代使用。)
如果您在较新的编译器上为较旧的系统构建二进制文件,则该运行时可能不知道 O_CLOEXEC
的值,因为该标志是随 pipe2()
一起引入的。如果它知道什么,它就知道 FD_CLOEXEC
。而且您不使用 F_SETFL
设置它,而是使用 F_SETFD
这是一个单独的 fcntl()
调用。
以下替换应该有效:
if (pipe(info_pipe) < 0)
goto info_pipe_err;
int direction; // 0=READ, 1=WRITE
for (direction = 0; direction < 2; ++direction) {
int oldflags;
oldflags = fcntl(info_pipe[direction], F_GETFL);
if (oldflags < 0)
goto info_pipe_err;
if (fcntl(info_pipe[direction],
F_SETFL, oldflags | O_NONBLOCK) < 0)
goto info_pipe_err;
oldflags = fcntl(info_pipe[direction], F_GETFD);
if (oldflags < 0)
goto info_pipe_err;
if (fcntl(info_pipe[direction],
F_SETFD, oldflags | FD_CLOEXEC) < 0)
goto info_pipe_err;
}
如前所述,这没有 pipe2()
提供的 thread-safety 方面允许一次完成所有这些。
我正在尝试构建一个可再发行的二进制文件以放置在只有 glibc 2.3 的旧 NAS 上。所以 pipe2()
在那台机器上不可用,但我要构建的代码有以下行:
if (pipe2(info_pipe, O_CLOEXEC | O_NONBLOCK) < 0)
goto info_pipe_err;
我的理解是 pipe2()
存在的原因是通过在打开时取 O_CLOEXEC | O_NONBLOCK
与分两步进行来避免竞争条件。但是我正在查看的情况下没有线程,所以我想我可以替换为:
if (pipe(info_pipe) < 0)
goto info_pipe_err;
int direction; // 0=READ, 1=WRITE
for (direction = 0; direction < 2; ++direction) {
int oldflags;
oldflags = fcntl(info_pipe[direction], F_GETFL);
if (oldflags < 0)
goto info_pipe_err;
if (fcntl(info_pipe[direction],
F_SETFL, oldflags | O_NONBLOCK | O_CLOEXEC) < 0)
goto info_pipe_err;
}
但它似乎不可互换,因为代码不起作用。为什么这不等价?
(回答我自己的问题因为我想通了,只是在这里发帖以供后代使用。)
如果您在较新的编译器上为较旧的系统构建二进制文件,则该运行时可能不知道 O_CLOEXEC
的值,因为该标志是随 pipe2()
一起引入的。如果它知道什么,它就知道 FD_CLOEXEC
。而且您不使用 F_SETFL
设置它,而是使用 F_SETFD
这是一个单独的 fcntl()
调用。
以下替换应该有效:
if (pipe(info_pipe) < 0)
goto info_pipe_err;
int direction; // 0=READ, 1=WRITE
for (direction = 0; direction < 2; ++direction) {
int oldflags;
oldflags = fcntl(info_pipe[direction], F_GETFL);
if (oldflags < 0)
goto info_pipe_err;
if (fcntl(info_pipe[direction],
F_SETFL, oldflags | O_NONBLOCK) < 0)
goto info_pipe_err;
oldflags = fcntl(info_pipe[direction], F_GETFD);
if (oldflags < 0)
goto info_pipe_err;
if (fcntl(info_pipe[direction],
F_SETFD, oldflags | FD_CLOEXEC) < 0)
goto info_pipe_err;
}
如前所述,这没有 pipe2()
提供的 thread-safety 方面允许一次完成所有这些。