【发布时间】:2020-11-27 19:43:51
【问题描述】:
下面的程序演示了这个问题。当您使用clang main.c -o main 构建它时,运行并按下几个键,您会看到程序总是在 Linux 上的“Calling poll()...”处停止。现在,如果您在最新的 WSL(Linux 的 Windows 子系统)上执行相同操作,您将看到它在“调用 read()...”处停止。换句话说,在 Linux 上是 poll() 阻塞,在 WSL 上是 read()。
该程序基本上将输入设置为非规范模式,VTIME 和 VMIN 也设置为 0。如果我正在阅读右下方的两个参考资料
- https://www.gnu.org/software/libc/manual/html_node/Canonical-or-Not.html
- https://www.gnu.org/software/libc/manual/html_node/Noncanonical-Input.html
然后我认为在这种情况下read() 不应该阻塞,我不应该看到程序在打印“调用 read()...”后等待。然而在 WSL 上却是这样。
现在,如果您在编译和运行时传递 -DNONBLOCK,在 Linux 和 WSL 上,程序总是在打印“Calling poll()...”后阻塞,这是预期的行为。
我想知道这是否是 WSL 上的错误,或者我误读了非规范模式文档。
程序:
// clang main.c -o main
#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;
}
}
}
}
【问题讨论】:
标签: c linux windows-subsystem-for-linux