-
Notifications
You must be signed in to change notification settings - Fork 1.5k
drivers/pipes: return after short write if buffer is full #14667
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
The write should return even in case of O_NONBLOCK if at least some bytes were written. The previous state where always all bytes were written was breaking a common combination with poll, because poll would signal POLLOUT and some bytes would really be consumed but write could still block afterwards. That would prevent from execution returning to the poll loop again. None the less it is also the standard C library behavior for the write function.
|
[Experimental Bot, please feedback here] Yes, this PR appears to meet the NuttX requirements, although some sections could be more explicit. Strengths:
Areas for Improvement:
Example of improved Testing Section: tlen 295 tlen 295 By making these improvements, the PR will be clearer, easier to review, and demonstrate a higher level of due diligence. |
|
Sorry @Cynerd: CI Test in arm-02 is failing with Pipe Timeout, I wonder if it's due to this PR? https://github.com/NuttX/nuttx/actions/runs/11713931118/job/32627704349#step:7:174 Update: CI Test is also super slow in sim-01 and risc-v-05, taking 6 hours (before getting killed by GitHub): |
It might be. I will look into that. I suspect that it is because of some invalid expectations for some components using the pipe. As I wrote in the "Impact": it might cause issues if code that uses pipecommon relies on write working in a non-standard way. Edit: The Edit2: @lupyuen apache/nuttx-apps#2829 |
|
hello @Cynerd there is a test failed in libuv [fs_partial_read] after this PR https://github.com/libuv/libuv/blob/v1.x/test/test-fs.c#L3764 and i find this explanation about write api in https://pubs.opengroup.org/onlinepubs/9799919799/ `Complete/partial/deferred: A write request: ret = write(fildes, buf, nbyte); Complete does this mean that if the nbytes < buffer_size, than the write should be block when the O_NONBLOCK flag is not set |
Yes, you are right. My change goes against POSIX for pipes and fifos. I even modified my test and run it on Linux and with sufficiently large buffer size it gets stuck as well: size_t tlen = 100000;
char text[tlen];
for (size_t i = 0; i < tlen; i++)
text[i] = 'x';
int fds[2];
assert(pipe2(fds, 0) == 0);
struct pollfd pfd[2] = {
{
.fd = fds[0],
.events = POLLIN | POLLHUP,
},
{
.fd = fds[1],
.events = POLLOUT,
},
};
size_t off = 0;
while (true) {
if (poll(pfd, 2, -1) == -1) {
printf("Poll fail %s\n", strerror(errno));
exit(1);
}
if (pfd[1].revents & POLLOUT) {
ssize_t wlen = write(fds[1], text + off, tlen - off);
if (wlen < 0) {
printf("Write fail %s\n", strerror(errno));
exit(1);
}
printf("Written %zd\n", wlen);
off += wlen;
if (off >= tlen)
close(fds[1]);
continue;
}
if (pfd[0].revents & POLLIN) {
char buf[BUFSIZ];
ssize_t rlen = read(fds[0], buf, BUFSIZ);
if (rlen < 0) {
printf("Read fail %s\n", strerror(errno));
exit(1);
}
fwrite(buf, 1, rlen, stdout);
}
if (pfd[0].revents & POLLHUP) {
putc('\n', stdout);
exit(0);
}
}I came to this from the socket (specifically local socket) side, and thus, I failed to check the POSIX specification for the pipe. Therefore, what is wrong here is not the behavior of pipe implementation but that unix local sockets are backed by them in NuttX. Thus, this change should be reverted as well as "fix" in apps for pipe test, and fix must be instead at the socket level. |
|
Could you please help revert these two patches first? @Cynerd |
|
I revert here: #14950 |
Summary
The write should return even in case of O_NONBLOCK if at least some bytes were written.
The previous state where always all bytes were written was breaking a common combination with poll, because poll would signal POLLOUT and some bytes would really be consumed but write could still block afterwards. That would prevent from execution returning to the poll loop again.
None the less it is also the standard C library behavior for the write function.
Impact
This could have impack on any code that uses pipes and fifos and relies on this non-standard behavior or
writealways writing all bytes. But it is non-standard behavior and thus considered to be a bug in my eyes.Testing
Tested with the following code that after this change works: