【问题标题】:Why is epoll_wait not responding to terminal input?为什么 epoll_wait 不响应终端输入?
【发布时间】:2020-09-14 17:13:40
【问题描述】:

以下代码在运行时不响应终端输入。我在 Debian 10.5.0 和 CentOS 7 下运行了它,结果相同。我错过了什么?

#include <sys/epoll.h>
#include <stdio.h>
#include <unistd.h>

int main(void) {

    char buffer[4096];
    int fd = epoll_create1(EPOLL_CLOEXEC);

    struct epoll_event event;
    int ctl_ret;
    event.events = EPOLLIN;
    event.data.fd = STDIN_FILENO;
    ctl_ret = epoll_ctl(fd, EPOLL_CTL_ADD, STDIN_FILENO, &event);
    if (ctl_ret) {
        perror("epoll_ctl");
        return 1;
    }

    int nr_event;
    for (;;) {
        fprintf(stderr, "Starting epoll_wait\n");
        nr_event = epoll_wait(fd, &event, 1, -1);
        if (nr_event < 0) {
            perror("epoll_wait");
            return 1;
        }
        fprintf(stderr, "Reading: %d\n", event.data.fd);
        printf("%ld\n", read(0, buffer, sizeof(buffer)));
    }

}

【问题讨论】:

  • epoll_create1 或 epoll_ctl 是否有任何错误?
  • 没有。我已经更新了上面的代码来检查 epoll_ctl() 和 epoll_wait() 错误。
  • 你的实现很好。执行for (;;) { long nbytes = 0; ... nbytes = read(0, buffer, sizeof(buffer)); buffer[nbytes-1] = 0; printf("%ld - %s\n", nbytes, buffer); if (strcmp (buffer, "quit") == 0) break;,您会看到epoll_wait 很高兴地等待fd 上的数据可用,然后read 将返回号码。读取的字节数(我们用0 覆盖buffer 中的'\n' 以将内容视为字符串),然后检查条目是否为"quit" 以退出。我没有发现任何问题。
  • 你试过不用epoll来看看你的程序是否真的在标准输入上得到任何数据吗?

标签: c stdin epoll


【解决方案1】:

正如 Basile Starynkevitch 所说,我需要通过 termios(3) 更新终端配置。

我在下面提供了修改后的代码以供参考。所需更改请参见// TERMINAL SETUP 和// EPOLL SETUP cmets 之间的代码。

#include <errno.h>
#include <linux/input.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/epoll.h>
#include <termios.h>
#include <unistd.h>

int main(void) {

    // TERMINAL SETUP
    struct termios tty_cfg, tty_cfg_cache;

    // Check that fd is a TTY
    if (!isatty(STDIN_FILENO)) {
        fprintf(stderr, "Standard input is not a terminal.\n");
        return EXIT_FAILURE;
    }

    // Save old terminal configuration
    if (tcgetattr(STDIN_FILENO, &tty_cfg_cache) == -1 ||
        tcgetattr(STDIN_FILENO, &tty_cfg) == -1) {
        fprintf(stderr, "Cannot get terminal settings: %s.\n", strerror(errno));
        return EXIT_FAILURE;
    }

    // Set new terminal configuration
    tty_cfg.c_iflag &= ~(IGNBRK | BRKINT | PARMRK);
    tty_cfg.c_lflag &= ~(ICANON | ISIG | ECHO | IEXTEN | TOSTOP);
    tty_cfg.c_cc[VMIN] = 0;
    tty_cfg.c_cc[VTIME] = 0;
    tty_cfg.c_cc[VSTART] = 0;
    tty_cfg.c_cc[VSTOP] = 0;
    if (tcsetattr(STDIN_FILENO, TCSANOW, &tty_cfg) == -1) {
        const int  saved_errno = errno;
        tcsetattr(STDIN_FILENO, TCSANOW, &tty_cfg_cache);
        fprintf(stderr, "Cannot set terminal settings: %s.\n", strerror(saved_errno));
        return EXIT_FAILURE;
    }

    // EPOLL SETUP
    // Create epoll
    int epfd = epoll_create1(EPOLL_CLOEXEC);

    // Add stdin control interface to epoll
    struct epoll_event event;
    int ctl_ret;
    event.events = EPOLLIN;
    event.data.fd = STDIN_FILENO;
    ctl_ret = epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &event);
    if (ctl_ret) {
        perror("epoll_ctl");
        return 1;
    }

    // LOOP AND MONITOR EPOLL
    int nr_event;
    unsigned char keys[16];
    ssize_t n;
    size_t i, done;
    done = 0;
    while (!done) {
        
        // Start epoll_wait
        nr_event = epoll_wait(epfd, &event, 1, -1);
        if (nr_event < 0) {
            perror("epoll_wait");
            return 1;
        }
        
        // Read STDIN_FILENO
        n = read(STDIN_FILENO, keys, sizeof keys);
        if (n > 0) {
            for (i = 0; i < n; i++) {
                // Quit if 'q' or 'Q' is pressed
                if (keys[i] == 'q' || keys[i] == 'Q')
                    done = 1;
                if (keys[i] >= 32 && keys[i] <= 126)
                    printf("Key '%c' = 0x%02x = %u pressed\n", keys[i], keys[i], keys[i]);
                else
                if (keys[i])
                    printf("Key '\\%03o' = 0x%02x = %u pressed\n", keys[i], keys[i], keys[i]);
                else
                    printf("NUL key (0) pressed\n");
            }
            fflush(stdout);
        }
    }
    
    // RESTORE TERMINAL SETTINGS
    tcsetattr(STDIN_FILENO, TCSAFLUSH, &tty_cfg_cache);

    return EXIT_SUCCESS;

}

【讨论】:

    猜你喜欢
    • 2021-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-30
    • 1970-01-01
    • 2010-11-21
    • 2012-01-24
    相关资源
    最近更新 更多