关键API:
epoll_wait, epoll_pwait, epoll_pwait2 等待epoll中的I/O事件发生。
概要:
#include <sys/epoll.h> int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout); int epoll_pwait(int epfd, struct epoll_event *events, int maxevents, int timeout, const sigset_t *sigmask); int epoll_pwait2(int epfd, struct epoll_event *events, int maxevents, const struct timespec *timeout, const sigset_t *sigmask);
参数描述:
epfd :epoll文件描述符
events :接口的返回参数,一般都是一个数组,数组长度大于等于maxevents。
maxevents:期望捕获的事件的个数。
timeout :超时时间(>=0),单位是毫秒ms,-1表示阻塞,0表示不阻塞。
sigmask:需要屏蔽信号的掩码,可以避免wait时被信号打断。
函数返回值:
ret: 函数返回值
正常捕获事件后返回事件的个数。
超时返回0.
只有在下面的情况下才会返回:
1、有至少一个事件发生。
2、调用过程中被信号中断?
3、超时。
events:函数输出参数
这个和create时是同一个数据结构,events就是很多事件的集合,data就是create时设置的值(原样返回)。
struct epoll_event { uint32_t events; /* Epoll events */ epoll_data_t data; /* User data variable */ };
拓展API:
epoll_pwait()
epoll_wait()与epoll_pwait()的区别类似,select(2)与pselect(2)。epoll_pwait()可以让程序安全的等到事件的发生,一般的epoll_wait()处理线程,在阻塞期间是可能被信号中断的。
当线程处理完信号函数以后,再次返回时,epoll_wait()不会继续阻塞,而是推出,返回-1。
调用方法:
ready = epoll_pwait(epfd, &events, maxevents, timeout, &sigmask);
实现:
函数的内部可以理解为原子的调用了下面的这些函数:
pthread_sigmask(SIG_SETMASK, &sigmask, &origmask); ready = epoll_wait(epfd, &events, maxevents, timeout); pthread_sigmask(SIG_SETMASK, &origmask, NULL);
参数:
sigmask: 希望阻塞的信号列表,如果为NULL,这个api和epoll_wait()功能一模一样。
epoll_pwait2()
和epoll_pwait()区别就是增加了超时时间。
调用:
int epoll_pwait2(int epfd, struct epoll_event *events, int maxevents, const struct timespec *timeout, const sigset_t *sigmask);
参数:
timeout:可以指定纳秒级别的时间。
返回值:
成功返回I/O事件的个数,超时返回0。失败返回-1,会设置错误码error。
错误码:
EBADF :apfd不是一个有效的描述符
EFAULT :参数events指向的内存区域不可写。
EINTR :阻塞过程中被信号中断,epoll_pwait()可以避免,或者错误处理中,解析error后重新调用epoll_wait()。
EINVAL :epfd不是一个epoll文件描述符,或者参数maxevents小于等于0。
注释:
1、当某个线程阻塞在epoll_wait(),另外一个线程可以往这个epfd中添加新的套接字。而且如果这个套接字事件发生,也会被阻塞的线程捕获事件。
2、如果epoll中已经有超过maxevents 个事件,当前成功返回后,再次调用,获取的事件将从上次取得结尾地方开始获取。可以理解为内部是一个队列,先进先出,事件再次
触发只能往后面插入,epoll_wait()从头取,避免出现饿死的情况。
3、如果epoll_wait()一个空的epfd,将会导致永远阻塞。如果epoll_wait()过程中,epfd监视列表被其它线程清空了也一样。