Mercurial > hg > nginx
comparison src/event/modules/ngx_epoll_module.c @ 6536:f7849bfb6d21
Improved EPOLLRDHUP handling.
When it's known that the kernel supports EPOLLRDHUP, there is no need in
additional recv() call to get EOF or error when the flag is absent in the
event generated by the kernel. A special runtime test is done at startup
to detect if EPOLLRDHUP is actually supported by the kernel because
epoll_ctl() silently ignores unknown flags.
With this knowledge it's now possible to drop the "ready" flag for partial
read. Previously, the "ready" flag was kept until the recv() returned EOF
or error. In particular, this change allows the lingering close heuristics
(which relies on the "ready" flag state) to actually work on Linux, and not
wait for more data in most cases.
The "available" flag is now used in the read event with the semantics similar
to the corresponding counter in kqueue.
author | Valentin Bartenev <vbart@nginx.com> |
---|---|
date | Fri, 13 May 2016 17:19:23 +0300 |
parents | 7640d6c213e1 |
children | 3ad1064a3aae |
comparison
equal
deleted
inserted
replaced
6535:db699978a33f | 6536:f7849bfb6d21 |
---|---|
121 | 121 |
122 #if (NGX_HAVE_FILE_AIO) | 122 #if (NGX_HAVE_FILE_AIO) |
123 static void ngx_epoll_eventfd_handler(ngx_event_t *ev); | 123 static void ngx_epoll_eventfd_handler(ngx_event_t *ev); |
124 #endif | 124 #endif |
125 | 125 |
126 static ngx_int_t ngx_epoll_module_init(ngx_cycle_t *cycle); | |
126 static void *ngx_epoll_create_conf(ngx_cycle_t *cycle); | 127 static void *ngx_epoll_create_conf(ngx_cycle_t *cycle); |
127 static char *ngx_epoll_init_conf(ngx_cycle_t *cycle, void *conf); | 128 static char *ngx_epoll_init_conf(ngx_cycle_t *cycle, void *conf); |
128 | 129 |
129 static int ep = -1; | 130 static int ep = -1; |
130 static struct epoll_event *event_list; | 131 static struct epoll_event *event_list; |
142 aio_context_t ngx_aio_ctx = 0; | 143 aio_context_t ngx_aio_ctx = 0; |
143 | 144 |
144 static ngx_event_t ngx_eventfd_event; | 145 static ngx_event_t ngx_eventfd_event; |
145 static ngx_connection_t ngx_eventfd_conn; | 146 static ngx_connection_t ngx_eventfd_conn; |
146 | 147 |
148 #endif | |
149 | |
150 #if (NGX_HAVE_EPOLLRDHUP) | |
151 ngx_uint_t ngx_use_epoll_rdhup; | |
147 #endif | 152 #endif |
148 | 153 |
149 static ngx_str_t epoll_name = ngx_string("epoll"); | 154 static ngx_str_t epoll_name = ngx_string("epoll"); |
150 | 155 |
151 static ngx_command_t ngx_epoll_commands[] = { | 156 static ngx_command_t ngx_epoll_commands[] = { |
195 NGX_MODULE_V1, | 200 NGX_MODULE_V1, |
196 &ngx_epoll_module_ctx, /* module context */ | 201 &ngx_epoll_module_ctx, /* module context */ |
197 ngx_epoll_commands, /* module directives */ | 202 ngx_epoll_commands, /* module directives */ |
198 NGX_EVENT_MODULE, /* module type */ | 203 NGX_EVENT_MODULE, /* module type */ |
199 NULL, /* init master */ | 204 NULL, /* init master */ |
200 NULL, /* init module */ | 205 ngx_epoll_module_init, /* init module */ |
201 NULL, /* init process */ | 206 NULL, /* init process */ |
202 NULL, /* init thread */ | 207 NULL, /* init thread */ |
203 NULL, /* exit thread */ | 208 NULL, /* exit thread */ |
204 NULL, /* exit process */ | 209 NULL, /* exit process */ |
205 NULL, /* exit master */ | 210 NULL, /* exit master */ |
806 | 811 |
807 #if (NGX_HAVE_EPOLLRDHUP) | 812 #if (NGX_HAVE_EPOLLRDHUP) |
808 if (revents & EPOLLRDHUP) { | 813 if (revents & EPOLLRDHUP) { |
809 rev->pending_eof = 1; | 814 rev->pending_eof = 1; |
810 } | 815 } |
816 | |
817 rev->available = 1; | |
811 #endif | 818 #endif |
812 | 819 |
813 rev->ready = 1; | 820 rev->ready = 1; |
814 | 821 |
815 if (flags & NGX_POST_EVENTS) { | 822 if (flags & NGX_POST_EVENTS) { |
941 } | 948 } |
942 | 949 |
943 #endif | 950 #endif |
944 | 951 |
945 | 952 |
953 static ngx_int_t | |
954 ngx_epoll_module_init(ngx_cycle_t *cycle) | |
955 { | |
956 #if (NGX_HAVE_EPOLLRDHUP) | |
957 int epfd, s[2], events; | |
958 struct epoll_event ee; | |
959 | |
960 epfd = epoll_create(1); | |
961 | |
962 if (epfd == -1) { | |
963 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | |
964 "epoll_create() failed"); | |
965 return NGX_ERROR; | |
966 } | |
967 | |
968 if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == -1) { | |
969 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | |
970 "socketpair() failed"); | |
971 return NGX_ERROR; | |
972 } | |
973 | |
974 ee.events = EPOLLET|EPOLLIN|EPOLLRDHUP; | |
975 | |
976 if (epoll_ctl(epfd, EPOLL_CTL_ADD, s[0], &ee) == -1) { | |
977 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | |
978 "epoll_ctl() failed"); | |
979 return NGX_ERROR; | |
980 } | |
981 | |
982 if (close(s[1]) == -1) { | |
983 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | |
984 "close() failed"); | |
985 return NGX_ERROR; | |
986 } | |
987 | |
988 events = epoll_wait(epfd, &ee, 1, 5000); | |
989 | |
990 if (events == -1) { | |
991 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | |
992 "epoll_wait() failed"); | |
993 return NGX_ERROR; | |
994 } | |
995 | |
996 (void) close(s[0]); | |
997 (void) close(epfd); | |
998 | |
999 if (events) { | |
1000 ngx_use_epoll_rdhup = ee.events & EPOLLRDHUP; | |
1001 | |
1002 } else { | |
1003 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | |
1004 "epoll_wait() timedout"); | |
1005 } | |
1006 | |
1007 ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, | |
1008 "testing the EPOLLRDHUP flag: %s", | |
1009 ngx_use_epoll_rdhup ? "success" : "fail"); | |
1010 #endif | |
1011 | |
1012 return NGX_OK; | |
1013 } | |
1014 | |
1015 | |
946 static void * | 1016 static void * |
947 ngx_epoll_create_conf(ngx_cycle_t *cycle) | 1017 ngx_epoll_create_conf(ngx_cycle_t *cycle) |
948 { | 1018 { |
949 ngx_epoll_conf_t *epcf; | 1019 ngx_epoll_conf_t *epcf; |
950 | 1020 |