Linux poll
介绍
本篇为 Linux I/O 事件通知机制系列第二篇,介绍 poll。 其他两篇为:
Table of Contents
- 介绍
- Table of Contents
- poll, ppoll - wait for some event on a file descriptor
- Description
- 返回值
- Errors
- Conforming To
- Notes
- Bugs
- 实例程序
- References
poll, ppoll - wait for some event on a file descriptor
Description
poll()
执行与 select(2) 类似的任务: 等待一系列文件描述符中任意一个为 I/O 读写准备就绪。
提到的文件描述符集合使用 fds 参数指定, 是一个下面结构体的数组:
调用者应该用 nfds 来指定 fds 数组的大小。
成员 fd 包含了一个打开的文件描述符。如果为负,则对应的 events 成员会被忽略,并且 revents 成员返回0。 (这就为在单次 poll() 调用中忽略一个文件描述符提供了一种简单方法:可以把 fd 成员设为负值。)
events 成员是个输入参数,使用位掩码指定了应用对文件描述符fd感兴趣的事件。如果这个成员为0,则fd的所有事件被忽略而且 revents 返回0。
revents 成员是个输出参数,是由内核按照实际发生的事件填充的。由 revents 返回的位中可以包含任何由 events 指定的, 或者 POLLERR, POLLHUP 和 POLLNVAL 三者之一。 (这三位在 events 成员中是无意义的, 当对应的情况为真的时候 revents 成员中对应的位会被设置。)
If none of the events requested (and no error) has occurred for any of the file descriptors, then poll() blocks until one of the events occurs.
timeout 参数指定了 poll() 将会阻塞的最小毫秒值。 (这个区间大小会按照系统时钟粒度向上取整,另外内核调度延时意味着可能会超过阻塞间隔一点点。) 指定一个负值给 timeout 意味着不存在超时。给 timeout 取0值会使 poll() 即使没有文件描述符就绪也立即返回。
The bits that may be set/returned in events and revents are defined in «a href=”http://linux.die.net/include/poll.h” rel=”nofollow”>poll.h</a>>:
- POLLIN
- 有数据要读
- POLLPRI
- 有紧急数据等待读取(e.g., out-of-band data on TCP socket; pseudoterminal master in packet mode has seen state change in slave).
- POLLOUT
- 现在写则不会阻塞
- POLLRDHUP (since Linux 2.6.17)
- Stream socket peer closed connection, or shut down writing half of connection. 必须定义
_GNU_SOURCE
(在包含任何头文件之前) 特性宏来获得这个定义 - POLLERR
- Error condition (output only)
- POLLHUP
- Hang up (output only)
- POLLNVAL
- 无效请求: fd 未打开 (output only)
When compiling with _XOPEN_SOURCE
defined, one also has the following, which convey no further information beyond the bits listed above:
POLLRDNORM
等同于 POLLIN
- POLLRDBAND
- Priority band data can be read (generally unused on Linux)
POLLWRNORM
等同于 POLLOUT
- POLLWRBAND
- Priority data may be written
Linux 了解但不使用 POLLMSG
ppoll()
- poll() 和 ppoll() 的关系类似于 select(2) 和 pselect(2) 的关系: 如同 pselect(2), ppoll() 允许一个应用安全的等待直到任意一个文件描述符变为就绪状态或者捕捉到一个信号。而不是 timeout 参数的精度不同,下面的 ppoll() 调用:
ready = ppoll(&fds, nfds, timeout_ts, &sigmask);
等同于原子执行下面的调用:
之所以 ppoll() 是必须的的原因请参见 pselect(2) 的描述。如果 sigmask 参数指定为 NULL, 信号掩码操作就不会被执行 (这样的话 ppoll() 和 poll() 就只有 timeout 参数的精度不同了).
timeout_ts 参数指定了ppoll() 将会阻塞的时间上限。这个参数是一个指向下面结构的指针:
如果 timeout_ts 参数设为 NULL, ppoll() 将会一直(
- indefinitely
- adv. 不确定地,无限期地;模糊地,不明确地
)阻塞。
返回值
成功时返回正值,代表具有非0 revents 成员的结构体的数目(换言之, 那些描述符有事件或者错误报告的)。 0表示超时,没有文件描述符就绪事件。错误的时候返回-1,且适当设置 errno。
Errors
- EFAULT
- 作为参数的数组不在调用程序的地址空间中。
- EINTR
- 在请求的事件发生之前有信号发生。参见 signal(7).
- EINVAL
- nfds 值超过了 RLIMIT_NOFILE 值。
- ENOMEM
- 没有足够的内存分配给文件描述符表。
Conforming To
poll()
conforms to POSIX.1-2001. ppoll()
is Linux-specific.
Notes
有些实现中定义了非标准常亮 INFTIM
为-1,用作 poll()
的 timeout
参数值。glibc 中没有提供这个常量。
关于如果在另一个线程中关闭了 poll()
监视的文件描述符的情况,请参考 select
(2)
Linux notes
Linux ppoll()
系统调用会修改 timeout_ts
参数。但是, glibc wrapper function 通过使用一个timeout的局部变量传递给系统调用而隐藏了这一行为。因此,glibc ppoll()
function 不修改 timeout_ts
参数。
Bugs
请参考 select
(2) BUGS 一节中有关假就绪通知的讨论。
实例程序
使用poll做简单服务器模型