leevis.com
leevis.com copied to clipboard
nginx处理epoll_wait EPOLLRDHUP错误
EPOLLRDHUP是什么意思
epoll_wait
返回的epoll_event
的events
的EPOLLRDHUP
被置位是什么意思呢,表示对端调用close()关闭socket连接或调用shutdown(SHUT_WR)关闭对端的写。
nginx是如何判断内核支持该错误的
这个参数应该是个新东西,也就是说不是所有的内核都支持。nginx又是怎么判断内核是否支持的呢?
在auto/os/linux 有这样一段代码,调用auto/feature 把ngx_feature_test的内容调用gcc编译一下,如果编译(且运行)成功则该系统支持该参数。
ngx_feature="EPOLLRDHUP"
ngx_feature_name="NGX_HAVE_EPOLLRDHUP"
ngx_feature_run=no
ngx_feature_incs="#include <sys/epoll.h>"
ngx_feature_path=
ngx_feature_libs=
ngx_feature_test="int efd = 0, fd = 0;
struct epoll_event ee;
ee.events = EPOLLIN|EPOLLRDHUP|EPOLLET;
ee.data.ptr = NULL;
epoll_ctl(efd, EPOLL_CTL_ADD, fd, &ee)"
. auto/feature
nginx是如何处理该参数
在调用模块的init_process
方法,调用到事件模块的ngx_event_process_init
方法时,该方法又调用事件模块的module->actions.init
,epoll是调用ngx_epoll_init
方法,该方法中调用epoll_create
创建完epoll文件句柄后,如果定义了宏NGX_HAVE_EPOLLRDHUP
,也就是通过feature
脚本判断支持EPOLLRDHUP
错误时,会调用ngx_epoll_test_rdhup
判断是否支持,该函数会建立一个socket的无名管道,epoll检查一端,关闭另一断端,查看检查的端是否会返回置位EPOLLRDHUP
的读事件。再多啰嗦点吧,别看这不到100行代码,注意的东西还挺多,因为是单进程单线程模拟一个socket双方通信,所以只能是先调用close
后epoll_wait
,都close完了再wait还能wait到事件吗?能,epoll 事件是可靠的。
ngx_epoll_test_rdhup(ngx_cycle_t *cycle)
{
int s[2], events;
struct epoll_event ee;
if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == -1) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
"socketpair() failed");
return;
}
ee.events = EPOLLET|EPOLLIN|EPOLLRDHUP;
if (epoll_ctl(ep, EPOLL_CTL_ADD, s[0], &ee) == -1) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
"epoll_ctl() failed");
goto failed;
}
if (close(s[1]) == -1) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
"close() failed");
s[1] = -1;
goto failed;
}
s[1] = -1;
events = epoll_wait(ep, &ee, 1, 5000);
if (events == -1) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
"epoll_wait() failed");
goto failed;
}
if (events) {
ngx_use_epoll_rdhup = ee.events & EPOLLRDHUP;
} else {
ngx_log_error(NGX_LOG_ALERT, cycle->log, NGX_ETIMEDOUT,
"epoll_wait() timed out");
}
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
"testing the EPOLLRDHUP flag: %s",
ngx_use_epoll_rdhup ? "success" : "fail");
failed:
if (s[1] != -1 && close(s[1]) == -1) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
"close() failed");
}
if (close(s[0]) == -1) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
"close() failed");
}
}