Klaus Demo nginx / fac4c7b
Events: available bytes calculation via ioctl(FIONREAD). This makes it possible to avoid looping for a long time while working with a fast enough peer when data are added to the socket buffer faster than we are able to read and process them (ticket #1431). This is basically what we already do on FreeBSD with kqueue, where information about the number of bytes in the socket buffer is returned by the kevent() call. With other event methods rev->available is now set to -1 when the socket is ready for reading. Later in ngx_recv() and ngx_recv_chain(), if full buffer is received, real number of bytes in the socket buffer is retrieved using ioctl(FIONREAD). Reading more than this number of bytes ensures that even with edge-triggered event methods the event will be triggered again, so it is safe to stop processing of the socket and switch to other connections. Using ioctl(FIONREAD) only after reading a full buffer is an optimization. With this approach we only call ioctl(FIONREAD) when there are at least two recv()/readv() calls. Maxim Dounin 27 days ago
17 changed file(s) with 193 addition(s) and 12 deletion(s). Raw diff Collapse all Expand all
942942 . auto/feature
943943
944944
945 ngx_feature="ioctl(FIONREAD)"
946 ngx_feature_name="NGX_HAVE_FIONREAD"
947 ngx_feature_run=no
948 ngx_feature_incs="#include <sys/ioctl.h>
949 #include <stdio.h>
950 $NGX_INCLUDE_SYS_FILIO_H"
951 ngx_feature_path=
952 ngx_feature_libs=
953 ngx_feature_test="int i = FIONREAD; printf(\"%d\", i)"
954 . auto/feature
955
956
945957 ngx_feature="struct tm.tm_gmtoff"
946958 ngx_feature_name="NGX_HAVE_GMTOFF"
947959 ngx_feature_run=no
494494
495495 if ((revents & POLLIN) && rev->active) {
496496 rev->ready = 1;
497 rev->available = -1;
497498
498499 if (flags & NGX_POST_EVENTS) {
499500 queue = rev->accept ? &ngx_posted_accept_events
885885 if (revents & EPOLLRDHUP) {
886886 rev->pending_eof = 1;
887887 }
888
889 rev->available = 1;
890888 #endif
891889
892890 rev->ready = 1;
891 rev->available = -1;
893892
894893 if (flags & NGX_POST_EVENTS) {
895894 queue = rev->accept ? &ngx_posted_accept_events
558558
559559 if (revents & POLLIN) {
560560 rev->ready = 1;
561 rev->available = -1;
561562
562563 if (flags & NGX_POST_EVENTS) {
563564 queue = rev->accept ? &ngx_posted_accept_events
369369
370370 ev = c->read;
371371 ev->ready = 1;
372 ev->available = -1;
372373
373374 queue = ev->accept ? &ngx_posted_accept_events
374375 : &ngx_posted_events;
329329
330330 if (found) {
331331 ev->ready = 1;
332 ev->available = -1;
332333
333334 queue = ev->accept ? &ngx_posted_accept_events
334335 : &ngx_posted_events;
379379
380380 ev = c->read;
381381 ev->ready = 1;
382 ev->available = -1;
382383
383384 queue = ev->accept ? &ngx_posted_accept_events
384385 : &ngx_posted_events;
329329
330330 if (found) {
331331 ev->ready = 1;
332 ev->available = -1;
332333
333334 queue = ev->accept ? &ngx_posted_accept_events
334335 : &ngx_posted_events;
9090 * write: available space in buffer when event is ready
9191 * or lowat when event is set with NGX_LOWAT_EVENT flag
9292 *
93 * epoll with EPOLLRDHUP:
94 * accept: 1 if accept many, 0 otherwise
95 * read: 1 if there can be data to read, 0 otherwise
96 *
9793 * iocp: TODO
9894 *
9995 * otherwise:
10096 * accept: 1 if accept many, 0 otherwise
97 * read: bytes to read when event is ready, -1 if not known
10198 */
10299
103 #if (NGX_HAVE_KQUEUE) || (NGX_HAVE_IOCP)
104100 int available;
105 #else
106 unsigned available:1;
107 #endif
108101
109102 ngx_event_handler_pt handler;
110103
5959 "readv: eof:%d, avail:%d",
6060 rev->pending_eof, rev->available);
6161
62 if (!rev->available && !rev->pending_eof) {
62 if (rev->available == 0 && !rev->pending_eof) {
6363 return NGX_AGAIN;
6464 }
6565 }
160160 }
161161
162162 return n;
163 }
164
165 #endif
166
167 #if (NGX_HAVE_FIONREAD)
168
169 if (rev->available >= 0) {
170 rev->available -= n;
171
172 /*
173 * negative rev->available means some additional bytes
174 * were received between kernel notification and readv(),
175 * and therefore ev->ready can be safely reset even for
176 * edge-triggered event methods
177 */
178
179 if (rev->available < 0) {
180 rev->available = 0;
181 rev->ready = 0;
182 }
183
184 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
185 "readv: avail:%d", rev->available);
186
187 } else if (n == size) {
188
189 if (ngx_socket_nread(c->fd, &rev->available) == -1) {
190 n = ngx_connection_error(c, ngx_socket_errno,
191 ngx_socket_nread_n " failed");
192 break;
193 }
194
195 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
196 "readv: avail:%d", rev->available);
163197 }
164198
165199 #endif
5656 "recv: eof:%d, avail:%d",
5757 rev->pending_eof, rev->available);
5858
59 if (!rev->available && !rev->pending_eof) {
59 if (rev->available == 0 && !rev->pending_eof) {
6060 rev->ready = 0;
6161 return NGX_AGAIN;
6262 }
111111 }
112112
113113 return n;
114 }
115
116 #endif
117
118 #if (NGX_HAVE_FIONREAD)
119
120 if (rev->available >= 0) {
121 rev->available -= n;
122
123 /*
124 * negative rev->available means some additional bytes
125 * were received between kernel notification and recv(),
126 * and therefore ev->ready can be safely reset even for
127 * edge-triggered event methods
128 */
129
130 if (rev->available < 0) {
131 rev->available = 0;
132 rev->ready = 0;
133 }
134
135 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
136 "recv: avail:%d", rev->available);
137
138 } else if ((size_t) n == size) {
139
140 if (ngx_socket_nread(c->fd, &rev->available) == -1) {
141 n = ngx_connection_error(c, ngx_socket_errno,
142 ngx_socket_nread_n " failed");
143 break;
144 }
145
146 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
147 "recv: avail:%d", rev->available);
114148 }
115149
116150 #endif
3737
3838 #endif
3939
40 #if (NGX_HAVE_FIONREAD)
41
42 #define ngx_socket_nread(s, n) ioctl(s, FIONREAD, n)
43 #define ngx_socket_nread_n "ioctl(FIONREAD)"
44
45 #endif
46
4047 int ngx_tcp_nopush(ngx_socket_t s);
4148 int ngx_tcp_push(ngx_socket_t s);
4249
2727
2828
2929 int
30 ngx_socket_nread(ngx_socket_t s, int *n)
31 {
32 unsigned long nread;
33
34 if (ioctlsocket(s, FIONREAD, &nread) == -1) {
35 return -1;
36 }
37
38 *n = nread;
39
40 return 0;
41 }
42
43
44 int
3045 ngx_tcp_push(ngx_socket_t s)
3146 {
3247 return 0;
2929
3030 #define ngx_nonblocking_n "ioctlsocket(FIONBIO)"
3131 #define ngx_blocking_n "ioctlsocket(!FIONBIO)"
32
33 int ngx_socket_nread(ngx_socket_t s, int *n);
34 #define ngx_socket_nread_n "ioctlsocket(FIONREAD)"
3235
3336 #define ngx_shutdown_socket shutdown
3437 #define ngx_shutdown_socket_n "shutdown()"
272272 #define NGX_HAVE_SO_SNDLOWAT 0
273273 #endif
274274
275 #ifndef NGX_HAVE_FIONREAD
276 #define NGX_HAVE_FIONREAD 1
277 #endif
278
275279 #define NGX_HAVE_GETADDRINFO 1
276280
277281 #define ngx_random rand
4949
5050 return n;
5151 }
52
53 #if (NGX_HAVE_FIONREAD)
54
55 if (rev->available >= 0 && bytes > 0) {
56 rev->available -= bytes;
57
58 /*
59 * negative rev->available means some additional bytes
60 * were received between kernel notification and WSARecv(),
61 * and therefore ev->ready can be safely reset even for
62 * edge-triggered event methods
63 */
64
65 if (rev->available < 0) {
66 rev->available = 0;
67 rev->ready = 0;
68 }
69
70 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
71 "WSARecv: avail:%d", rev->available);
72
73 } else if (bytes == size) {
74
75 if (ngx_socket_nread(c->fd, &rev->available) == -1) {
76 n = ngx_connection_error(c, ngx_socket_errno,
77 ngx_socket_nread_n " failed");
78
79 if (n == NGX_ERROR) {
80 rev->error = 1;
81 }
82
83 return n;
84 }
85
86 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
87 "WSARecv: avail:%d", rev->available);
88 }
89
90 #endif
5291
5392 if (bytes < size) {
5493 rev->ready = 0;
9393 return NGX_ERROR;
9494 }
9595
96 #if (NGX_HAVE_FIONREAD)
97
98 if (rev->available >= 0 && bytes > 0) {
99 rev->available -= bytes;
100
101 /*
102 * negative rev->available means some additional bytes
103 * were received between kernel notification and WSARecv(),
104 * and therefore ev->ready can be safely reset even for
105 * edge-triggered event methods
106 */
107
108 if (rev->available < 0) {
109 rev->available = 0;
110 rev->ready = 0;
111 }
112
113 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
114 "WSARecv: avail:%d", rev->available);
115
116 } else if (bytes == size) {
117
118 if (ngx_socket_nread(c->fd, &rev->available) == -1) {
119 rev->error = 1;
120 ngx_connection_error(c, ngx_socket_errno,
121 ngx_socket_nread_n " failed");
122 return NGX_ERROR;
123 }
124
125 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
126 "WSARecv: avail:%d", rev->available);
127 }
128
129 #endif
130
96131 if (bytes < size) {
97132 rev->ready = 0;
98133 }