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