• poll相关


    IO多路复用。

    1. 定义

    #include <poll.h>
    
    struct pollfd {
        int   fd;         /* file descriptor */
        short events;     /* requested events */
        short revents;    /* returned events */
    };
    
    int poll(struct pollfd *fds, nfds_t nfds, int timeout);
    
    #define _GNU_SOURCE         /* See feature_test_macros(7) */
    #include <poll.h>
    
    struct timespec {
        long    tv_sec;         /* seconds */
        long    tv_nsec;        /* nanoseconds */
    };
    
    int ppoll(struct pollfd *fds, nfds_t nfds,
            const struct timespec *timeout_ts, const sigset_t *sigmask);
    

    2. 基本使用

    select(2)类似,等待一组文件描述符上的事件。

    如果 fd 是负数,poll(2) 会忽略 events,并且返回的revents是0,可以在单次poll(2)调用中,忽略某一个fd
    events 是入参,输入对fd上感兴趣的事件,是个bitmask,0表示对所有事件都不感兴趣。

    revents是出参,表示哪些事件发生了,也是个bitmask,可能会比 events 多出来三个值 POLLER, POLLHUP, POLLNVAL

    timeout是ms,表示poll(2)最少会阻塞的时间,0表示非阻塞,立刻返回,即使没有事件发生也会返回;负数表示一直阻塞,直到有事件发生。

    bitmask可以有的值为:

    • POLLIN: 有数据可以读
    • POLLPRI: 紧急数据可读(TCP上的带外数据等)
    • POLLOUT: 数据可写,这时候进行写操作不会阻塞
    • POLLRDHUP(>=2.6.17): 流式socket的对端断开连接或者关闭了写操作。比如有 _GNU_SOURCE 宏才能使用该定义
    • POLLERR(out): 有错误发生
    • POLLHUP(out): 挂起。写端关闭,在读端poll()时,会出现该错误。
    • POLLNVAL(out): 非法请求,fd未打开。等价于EBADF。

    ppoll(2) 允许应用安全的等待fd上事件发生,或者捕获了信号。类似 select(2)pselect(2) 的关系。
    这样的调用:

    ready = ppoll(&fds, nfds, timeout_ts, &sigmask);
    

    等价于 原子性 的执行:

    sigset_t origmask;
    int timeout;
    
    timeout = (timeout_ts == NULL) ? -1 :
                (timeout_ts.tv_sec * 1000 + timeout_ts.tv_nsec / 1000000);
    sigprocmask(SIG_SETMASK, &sigmask, &origmask);
    ready = poll(&fds, nfds, timeout);
    sigprocmask(SIG_SETMASK, &origmask, NULL);
    

    3. 返回值

    大于0: 成功,有事件发生的fd的个数(这些fd上的 revents 非0)。
    0: 超时,没有事件发生
    -1: 失败,需要检查对应的errno。

    errno:

    • EFAULT: 参数数组地址无效
    • EINTR: 有信号发生
    • EINVAL: nfds 值超出了 RLIMIT_NOFILE 的值
    • ENOMEM: 没有内存来申请fd表

    4. 其他

    有些实现定义了 timeout 参数无穷大值 INFTIM,值为-1, glibc 没有定义。

    linux提供的 ppoll(2) 系统调用接口会更新 timeout_ts 参数,glibc封装的时候不会更新,需要注意

    5. 关于POLLHUP

    这里稍详细的解释了POLLHUP: https://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html

    POLLHUP
    A device has been disconnected, or a pipe or FIFO has been closed by the last process that had it open for writing. Once set, the hangup state of a FIFO shall persist until some process opens the FIFO for writing or until all read-only file descriptors for the FIFO are closed. This event and POLLOUT are mutually-exclusive; a stream can never be writable if a hangup has occurred. However, this event and POLLIN, POLLRDNORM, POLLRDBAND, or POLLPRI are not mutually-exclusive. This flag is only valid in the revents bitmask; it shall be ignored in the events member.
    POLLNVAL

    也就是写端关闭,在读端进行poll()时,会报出这个错,然后在写端重新打开后,该fd还会正常,有人提供了个示例,演示了如何触发 POLLHUP

    // 打开pipe, 关闭写端,在读端进行poll()
    
    #include <unistd.h>
    #include <stdio.h>
    #include <poll.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <string.h>
    
    int main(void)
    {
        int p[2];
        struct pollfd ufd;
    
        if (pipe(p) < 0) {
            perror("pipe");
            return EXIT_FAILURE;
        }
        if (close(p[1]) < 0) { /* close the write fd */
            perror("close");
            return EXIT_FAILURE;
        }
    
        memset(&ufd, 0, sizeof ufd);
        ufd.fd = p[0]; /* poll the read fd after the write fd is closed */
        ufd.events = POLLIN;
        if (poll(&ufd, 1, 1000) < 0) {
            perror("poll");
            return EXIT_FAILURE;
        }
    
        switch(ufd.revents & (POLLIN|POLLHUP)) {
            case POLLIN: printf("POLLIN
    "); break;
            case POLLHUP: printf("POLLHUP
    "); break;
            case POLLIN|POLLHUP: printf("POLLIN|POLLHUP
    "); break;
            case POLLERR: printf("POLLERR
    "); break;
            default: printf("%#x
    ", (unsigned)ufd.revents); break;
        }
    
        return EXIT_SUCCESS;
    }
    
  • 相关阅读:
    JDBC
    Ajax:一种不用刷新整个页面便可与服务器通讯的办法
    Maven——自动化构建工具
    SSM整合
    MyBatis框架
    SpringMVC框架、Spring boot框架、SSM區別
    Spring开源框架
    切入点表达式
    面向切面编程之cglib代理方式
    动态JDK代理方式-实现类增强
  • 原文地址:https://www.cnblogs.com/suntus/p/14908743.html
Copyright © 2020-2023  润新知