關鍵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監視列表被其它線程清空了也一樣。
