-
Notifications
You must be signed in to change notification settings - Fork 797
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
termios non canonical mode reads should not block #3507
Comments
I can confirm I have this issue as well. When I set a serial port for non-blocking mode, it appears to block regardless. I tested a similar script as the one above on a standard linux Ubuntu distro against the latest WSL w/ ubuntu and had the same behavior. It also seems to ignore the MIN setting if you set MIN to a number, it returns less than MIN on a blocking read with TIME set to 0? @markpizz I know your issue is specifically with it always blocking, but did you happen to be able to test if while blocking and setting MIN to a larger number, did the read return less than MIN chars as well? Just curious. Thanks! |
I did not test what you're asking. The test program in the report is a minimal use of what my application does/needs. Sorry. |
I confirm this error is still present, at least, in WSL 1. As a workaround, I solved my problem coding with the function select(), as presented in this stack overflow answer. |
I was following this tutorial and I had this issue even in WSL 2. |
Normally term_input is used with non-canonical input with VMIN=0 and VTIME=0. On Linux in this mode stdin does not block (returns 0 when it's not ready for reading, see [1] and [2]). However on WSL it doesn't work that way and we have to set stdin to non-blocking mode to be able to do `read(stdin)` without blocking. We now set stdin to non-blocking mode when creating an `Input` and restore the old flags when dropping it. Fixes #269 [1]: https://www.gnu.org/software/libc/manual/html_node/Canonical-or-Not.html [2]: https://www.gnu.org/software/libc/manual/html_node/Noncanonical-Input.html
Here's another reproducer: C program// clang -Wall main.c -o main -DNONBLOCK
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
void main_loop();
bool read_until_empty();
int main()
{
#if defined(NONBLOCK)
int old_stdin_flags = fcntl(STDIN_FILENO, F_GETFL);
fcntl(STDIN_FILENO, F_SETFL, old_stdin_flags | O_NONBLOCK);
printf("Enabled non-blocking mode\n");
#endif
bool fail = false;
int tty = open("/dev/tty", O_RDWR);
if (tty == -1) {
printf("Unable to open /dev/tty\n");
fail = true;
goto cleanup;
}
struct termios old_termios;
if (tcgetattr(STDIN_FILENO, &old_termios) == -1) {
printf("tcgetattr failed\n");
fail = true;
goto cleanup;
}
struct termios new_termios = old_termios;
cfmakeraw(&new_termios);
// These really need to be after cfmakeraw() !!!!
new_termios.c_cc[VMIN] = 0;
new_termios.c_cc[VTIME] = 0;
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &new_termios) == -1) {
printf("tcsetattr failed\n");
fail = true;
goto cleanup;
}
printf("Type 'q' to quit.\n");
main_loop();
cleanup:
tcsetattr(STDIN_FILENO, TCSAFLUSH, &old_termios);
#if defined(NONBLOCK)
fcntl(STDIN_FILENO, F_SETFL, old_stdin_flags);
printf("Restored stdin flags\n");
#endif
if (fail) {
return 1;
}
}
void main_loop()
{
printf("main_loop\n");
struct pollfd fds[1] = { { .fd = STDIN_FILENO, .events = POLLIN } };
for (;;)
{
printf("Calling poll()...\n");
int poll_ret = poll(fds, 1, -1);
if (poll_ret > 0)
{
printf("stdin ready for reading\n");
if (read_until_empty())
{
return;
}
}
}
}
bool read_until_empty()
{
uint8_t buf[10000];
for (;;)
{
printf("Calling read()...\n");
ssize_t n_read = read(STDIN_FILENO, buf, 10000);
if (n_read == -1)
{
if (errno == EAGAIN || errno == EWOULDBLOCK)
{
printf("EAGAIN or EWOULDBLOCK\n");
return false;
}
else
{
printf("Error %d: %s\n", errno, strerror(errno));
return false;
}
}
else if (n_read == 0)
{
printf("stdin is empty\n");
return false;
}
else
{
printf("Read %zd bytes\n", n_read);
if (buf[0] == 3 || buf[0] == 113)
{
return true;
}
}
}
} If you run this on Linux (ignore the CPP) you'll see that the program always blocks after printing "Calling poll()...". On WSL it blocks after printing "Calling read()...". In other words, on Linux |
Thank-you for the tight repro; they are always appreciated. WSL1 still does not respect Better on WSL2. |
This issue has been automatically closed since it has not had any activity for the past year. If you're still experiencing this issue please re-file this as a new issue or feature request. Thank you! |
ver
at a Windows Command Prompt)Microsoft Windows [Version 10.0.17134.228]
tcsetattr() configures non canonical mode, but reads in non-canonical mode block indefinitely. The below example program blocks on WSL, and doesn't on Linux.
The termios man page describes non-canonical mode behaviors:
My use case sets VMIN and VTIME to 0, which absolutely should not block, and specifically fixing this case shouldn't be hard since if I explicitly use fcntrl to set the fd to non blocking, it doesn't block. This could be done under the covers even a thorough interpretation of VMIN and VTIME might be much harder to do.
The text was updated successfully, but these errors were encountered: