poll, ppoll

poll,ppoll


poll, ppoll - 等待文件描述符的一些事件
SYNOPSIS
       #include <poll.h>


       int poll(struct pollfd *fds, nfds_t nfds, int timeout);


       #define _GNU_SOURCE         /* See feature_test_macros(7) */
       #include <signal.h>
       #include <poll.h>


       int ppoll(struct pollfd *fds, nfds_t nfds,
               const struct timespec *timeout_ts, const sigset_t *sigmask);


DESCRIPTION
       poll() 类似于select,等待一组文件描述符直到I/O处于可用状态
       
       这组文件描述符是fds数组传入的,成员结构如下:
           struct pollfd {
               int   fd;         /* 文件描述符 */
               short events;     /* 请求事件 */
               short revents;    /* 返回事件 */
           };
        调用者必须通过nfds参数指出fds数组成员的个数.
        
        fd是已经打开的文件的文件描述符,如果fd不可用,或者是非法的,在结构中给出的events会被忽略,同时revents返回0(这样做提供了一个在调用poll函数时忽略文件描述符的简单方法.(使文件描述符无效,就可以在poll的时候忽略掉该fds成员的监控,注意:不能把fd设置成0); 
        
        events:是一个输入型参数,每个bit位指定一个和fd相关的事件,events可以是0,当events是0的时候,revents只能返回三种事件POLLHUP, POLLERR, POLLNVAL.


        revents:是一个输出型参数,内核根据实际发生的事件来填写revents,revents可以返回任何一个在events中填写的事件,或者是POLLERR, POLLHUP, POLLNVAL中的一个.
       
        如果所有fds中的数组成员指定的events中请求的事件都没有发生,poll()将一直阻塞,直到有事件发生.
        
        timeout:指定在没有事件发生时,可以阻塞多少毫秒(ms).
        
        注意:由于每个系统的系统时钟的问题,实际阻塞的时间可能会超出timeout指定的时间. 如果设置timeout为负值,意味着poll将一直等待下去,直到事件发生.如果设置为0,poll会立即返回,不管事件是否发生和.
        
        在events和revents中的bit位定义在<poll.h>中
                
              POLLIN 
                    有数据可读
              POLLPRI
                    有紧急的数据要读.(通过send可以设置收取的是否为紧急数据)
                    http://www.masterraghu.com/subjects/np/introduction/unix_network_programming_v1.3/ch24lev1sec2.html
              POLLOUT
                    可以写入,但如果没有把fd设置成O_NONBLOCK,较大的数据将会继续阻塞.
              POLLRDHUP (since Linux 2.6.17)
                    socket链接的对端关闭了链接,或者是链接异常.
              POLLERR
                    poll函数异常
              POLLHUP
                    poll函数挂起
              POLLNVAL
                    fd没有打开.(socket或者文件没有被打开,或者不存在)


        在编译时定义了 _XOPEN_SOURCE, 会有下面的事件


              POLLRDNORM
                    等同于POLLIN
                    
              POLLWRNORM
                    等同于POLLOUT
              POLLWRBAND
                    优先数据可以写入


   ppoll()
        poll和ppoll很相似,就像select和pselect.ppoll允许程序安全的等待,直到文件描述符已经准备好了,或者捕捉到一个退出的信号.


        在timeout参数上,ppoll比poll精确.
           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);


        查看pselect,理解ppoll为什么是首选.


        如果sigmask参数是NULL, ppoll不会监控任何事件,和poll唯一的区别就是timeout参数.


        timeout_ts参数给出一个ppoll阻塞的上限时间.timeout_ts是一个指针,timeout_ts的结构如下:
           struct timespec {
               long    tv_sec;         /* seconds */
               long    tv_nsec;        /* nanoseconds */
           };




        timeout_ts如果是NULL,ppoll将一直阻塞到事件发生.
RETURN VALUE
        成功:返回一个正数,返回值为非0的revents的位数.如果返回0,表示ppoll是超时返回.
        错误:返回-1,并且会设置系统的errno.
ERRORS
       EFAULT The array given as argument was not contained in the calling program's address space.
                数组参数不可用
       EINTR  A signal occurred before any requested event; see signal(7).
                捕捉到特殊的信号,具体的信号请查看signal手册.
       EINVAL The nfds value exceeds the RLIMIT_NOFILE value.
                nfds的数组大小超出了RLIMIT_NOFILE
       ENOMEM There was no space to allocate file descriptor tables.
                没有空间用于创建文件描述符表
VERSIONS
        poll函数在2.1.23之后提供的,在老的内核中没有poll系统调用.在之前的版本可用使用select.
        
CONFORMING TO
        poll遵循POSIX.1-2001,ppoll是linux引入的
NOTES
        某些版本会定义非标准的常量INFTIM = -1,用于poll的timeout参数, 在glibc中不支持INFTIM常量.

原文地址:https://www.cnblogs.com/hacker007/p/10070063.html