Klaus Demo nginx / 12f4367
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. Valentin Bartenev 6 years ago
6 changed file(s) with 153 addition(s) and 3 deletion(s). Raw diff Collapse all Expand all
122122 static void ngx_epoll_eventfd_handler(ngx_event_t *ev);
123123 #endif
124124
125 static ngx_int_t ngx_epoll_module_init(ngx_cycle_t *cycle);
125126 static void *ngx_epoll_create_conf(ngx_cycle_t *cycle);
126127 static char *ngx_epoll_init_conf(ngx_cycle_t *cycle, void *conf);
127128
143144 static ngx_event_t ngx_eventfd_event;
144145 static ngx_connection_t ngx_eventfd_conn;
145146
147 #endif
148
149 #if (NGX_HAVE_EPOLLRDHUP)
150 ngx_uint_t ngx_use_epoll_rdhup;
146151 #endif
147152
148153 static ngx_str_t epoll_name = ngx_string("epoll");
196201 ngx_epoll_commands, /* module directives */
197202 NGX_EVENT_MODULE, /* module type */
198203 NULL, /* init master */
199 NULL, /* init module */
204 ngx_epoll_module_init, /* init module */
200205 NULL, /* init process */
201206 NULL, /* init thread */
202207 NULL, /* exit thread */
807812 if (revents & EPOLLRDHUP) {
808813 rev->pending_eof = 1;
809814 }
815
816 rev->available = 1;
810817 #endif
811818
812819 rev->ready = 1;
942949 #endif
943950
944951
952 static ngx_int_t
953 ngx_epoll_module_init(ngx_cycle_t *cycle)
954 {
955 #if (NGX_HAVE_EPOLLRDHUP)
956 int epfd, s[2], events;
957 struct epoll_event ee;
958
959 epfd = epoll_create(1);
960
961 if (epfd == -1) {
962 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
963 "epoll_create() failed");
964 return NGX_ERROR;
965 }
966
967 if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == -1) {
968 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
969 "socketpair() failed");
970 return NGX_ERROR;
971 }
972
973 ee.events = EPOLLET|EPOLLIN|EPOLLRDHUP;
974
975 if (epoll_ctl(epfd, EPOLL_CTL_ADD, s[0], &ee) == -1) {
976 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
977 "epoll_ctl() failed");
978 return NGX_ERROR;
979 }
980
981 if (close(s[1]) == -1) {
982 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
983 "close() failed");
984 return NGX_ERROR;
985 }
986
987 events = epoll_wait(epfd, &ee, 1, 5000);
988
989 if (events == -1) {
990 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
991 "epoll_wait() failed");
992 return NGX_ERROR;
993 }
994
995 (void) close(s[0]);
996 (void) close(epfd);
997
998 if (events) {
999 ngx_use_epoll_rdhup = ee.events & EPOLLRDHUP;
1000
1001 } else {
1002 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
1003 "epoll_wait() timedout");
1004 }
1005
1006 ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0,
1007 "testing the EPOLLRDHUP flag: %s",
1008 ngx_use_epoll_rdhup ? "success" : "fail");
1009 #endif
1010
1011 return NGX_OK;
1012 }
1013
1014
9451015 static void *
9461016 ngx_epoll_create_conf(ngx_cycle_t *cycle)
9471017 {
9595 * write: available space in buffer when event is ready
9696 * or lowat when event is set with NGX_LOWAT_EVENT flag
9797 *
98 * epoll with EPOLLRDHUP:
99 * accept: 1 if accept many, 0 otherwise
100 * read: 1 if there can be data to read, 0 otherwise
101 *
98102 * iocp: TODO
99103 *
100104 * otherwise:
195199
196200
197201 extern ngx_event_actions_t ngx_event_actions;
202 #if (NGX_HAVE_EPOLLRDHUP)
203 extern ngx_uint_t ngx_use_epoll_rdhup;
204 #endif
198205
199206
200207 /*
27512751
27522752 #if (NGX_HAVE_EPOLLRDHUP)
27532753
2754 if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) && rev->pending_eof) {
2754 if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) && ngx_use_epoll_rdhup) {
27552755 socklen_t len;
2756
2757 if (!rev->pending_eof) {
2758 return;
2759 }
27562760
27572761 rev->eof = 1;
27582762 c->error = 1;
12211221
12221222 #if (NGX_HAVE_EPOLLRDHUP)
12231223
1224 if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) && ev->pending_eof) {
1224 if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) && ngx_use_epoll_rdhup) {
12251225 socklen_t len;
1226
1227 if (!ev->pending_eof) {
1228 return;
1229 }
12261230
12271231 ev->eof = 1;
12281232 c->error = 1;
5252
5353 #endif
5454
55 #if (NGX_HAVE_EPOLLRDHUP)
56
57 if (ngx_event_flags & NGX_USE_EPOLL_EVENT) {
58 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
59 "readv: eof:%d, avail:%d",
60 rev->pending_eof, rev->available);
61
62 if (!rev->available && !rev->pending_eof) {
63 return NGX_AGAIN;
64 }
65 }
66
67 #endif
68
5569 prev = NULL;
5670 iov = NULL;
5771 size = 0;
150164
151165 #endif
152166
167 #if (NGX_HAVE_EPOLLRDHUP)
168
169 if ((ngx_event_flags & NGX_USE_EPOLL_EVENT)
170 && ngx_use_epoll_rdhup)
171 {
172 if (n < size) {
173 if (!rev->pending_eof) {
174 rev->ready = 0;
175 }
176
177 rev->available = 0;
178 }
179
180 return n;
181 }
182
183 #endif
184
153185 if (n < size && !(ngx_event_flags & NGX_USE_GREEDY_EVENT)) {
154186 rev->ready = 0;
155187 }
4444 rev->ready = 0;
4545 return NGX_AGAIN;
4646 }
47 }
48 }
49
50 #endif
51
52 #if (NGX_HAVE_EPOLLRDHUP)
53
54 if (ngx_event_flags & NGX_USE_EPOLL_EVENT) {
55 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
56 "recv: eof:%d, avail:%d",
57 rev->pending_eof, rev->available);
58
59 if (!rev->available && !rev->pending_eof) {
60 rev->ready = 0;
61 return NGX_AGAIN;
4762 }
4863 }
4964
100115
101116 #endif
102117
118 #if (NGX_HAVE_EPOLLRDHUP)
119
120 if ((ngx_event_flags & NGX_USE_EPOLL_EVENT)
121 && ngx_use_epoll_rdhup)
122 {
123 if ((size_t) n < size) {
124 if (!rev->pending_eof) {
125 rev->ready = 0;
126 }
127
128 rev->available = 0;
129 }
130
131 return n;
132 }
133
134 #endif
135
103136 if ((size_t) n < size
104137 && !(ngx_event_flags & NGX_USE_GREEDY_EVENT))
105138 {