Groonga 3.0.9 Source Code Document
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ngx_readv_chain.c
Go to the documentation of this file.
1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) Nginx, Inc.
5  */
6 
7 
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_event.h>
11 
12 
13 #define NGX_IOVS 16
14 
15 
16 #if (NGX_HAVE_KQUEUE)
17 
18 ssize_t
20 {
21  u_char *prev;
22  ssize_t n, size;
23  ngx_err_t err;
24  ngx_array_t vec;
25  ngx_event_t *rev;
26  struct iovec *iov, iovs[NGX_IOVS];
27 
28  rev = c->read;
29 
32  "readv: eof:%d, avail:%d, err:%d",
33  rev->pending_eof, rev->available, rev->kq_errno);
34 
35  if (rev->available == 0) {
36  if (rev->pending_eof) {
37  rev->ready = 0;
38  rev->eof = 1;
39 
40  ngx_log_error(NGX_LOG_INFO, c->log, rev->kq_errno,
41  "kevent() reported about an closed connection");
42 
43  if (rev->kq_errno) {
44  rev->error = 1;
45  ngx_set_socket_errno(rev->kq_errno);
46  return NGX_ERROR;
47  }
48 
49  return 0;
50 
51  } else {
52  return NGX_AGAIN;
53  }
54  }
55  }
56 
57  prev = NULL;
58  iov = NULL;
59  size = 0;
60 
61  vec.elts = iovs;
62  vec.nelts = 0;
63  vec.size = sizeof(struct iovec);
64  vec.nalloc = NGX_IOVS;
65  vec.pool = c->pool;
66 
67  /* coalesce the neighbouring bufs */
68 
69  while (chain) {
70  if (prev == chain->buf->last) {
71  iov->iov_len += chain->buf->end - chain->buf->last;
72 
73  } else {
74  if (vec.nelts >= IOV_MAX) {
75  break;
76  }
77 
78  iov = ngx_array_push(&vec);
79  if (iov == NULL) {
80  return NGX_ERROR;
81  }
82 
83  iov->iov_base = (void *) chain->buf->last;
84  iov->iov_len = chain->buf->end - chain->buf->last;
85  }
86 
87  size += chain->buf->end - chain->buf->last;
88  prev = chain->buf->end;
89  chain = chain->next;
90  }
91 
93  "readv: %d, last:%d", vec.nelts, iov->iov_len);
94 
95  rev = c->read;
96 
97  do {
98  n = readv(c->fd, (struct iovec *) vec.elts, vec.nelts);
99 
100  if (n >= 0) {
101  if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
102  rev->available -= n;
103 
104  /*
105  * rev->available may be negative here because some additional
106  * bytes may be received between kevent() and recv()
107  */
108 
109  if (rev->available <= 0) {
110  if (!rev->pending_eof) {
111  rev->ready = 0;
112  }
113 
114  if (rev->available < 0) {
115  rev->available = 0;
116  }
117  }
118 
119  if (n == 0) {
120 
121  /*
122  * on FreeBSD recv() may return 0 on closed socket
123  * even if kqueue reported about available data
124  */
125 
126 #if 0
128  "readv() returned 0 while kevent() reported "
129  "%d available bytes", rev->available);
130 #endif
131 
132  rev->eof = 1;
133  rev->available = 0;
134  }
135 
136  return n;
137  }
138 
139  if (n < size) {
140  rev->ready = 0;
141  }
142 
143  if (n == 0) {
144  rev->eof = 1;
145  }
146 
147  return n;
148  }
149 
150  err = ngx_socket_errno;
151 
152  if (err == NGX_EAGAIN || err == NGX_EINTR) {
154  "readv() not ready");
155  n = NGX_AGAIN;
156 
157  } else {
158  n = ngx_connection_error(c, err, "readv() failed");
159  break;
160  }
161 
162  } while (err == NGX_EINTR);
163 
164  rev->ready = 0;
165 
166  if (n == NGX_ERROR) {
167  c->read->error = 1;
168  }
169 
170  return n;
171 }
172 
173 #else /* ! NGX_HAVE_KQUEUE */
174 
175 ssize_t
177 {
178  u_char *prev;
179  ssize_t n, size;
180  ngx_err_t err;
181  ngx_array_t vec;
182  ngx_event_t *rev;
183  struct iovec *iov, iovs[NGX_IOVS];
184 
185  prev = NULL;
186  iov = NULL;
187  size = 0;
188 
189  vec.elts = iovs;
190  vec.nelts = 0;
191  vec.size = sizeof(struct iovec);
192  vec.nalloc = NGX_IOVS;
193  vec.pool = c->pool;
194 
195  /* coalesce the neighbouring bufs */
196 
197  while (chain) {
198  if (prev == chain->buf->last) {
199  iov->iov_len += chain->buf->end - chain->buf->last;
200 
201  } else {
202  if (vec.nelts >= IOV_MAX) {
203  break;
204  }
205 
206  iov = ngx_array_push(&vec);
207  if (iov == NULL) {
208  return NGX_ERROR;
209  }
210 
211  iov->iov_base = (void *) chain->buf->last;
212  iov->iov_len = chain->buf->end - chain->buf->last;
213  }
214 
215  size += chain->buf->end - chain->buf->last;
216  prev = chain->buf->end;
217  chain = chain->next;
218  }
219 
221  "readv: %d:%d", vec.nelts, iov->iov_len);
222 
223  rev = c->read;
224 
225  do {
226  n = readv(c->fd, (struct iovec *) vec.elts, vec.nelts);
227 
228  if (n == 0) {
229  rev->ready = 0;
230  rev->eof = 1;
231 
232  return n;
233 
234  } else if (n > 0) {
235 
236  if (n < size && !(ngx_event_flags & NGX_USE_GREEDY_EVENT)) {
237  rev->ready = 0;
238  }
239 
240  return n;
241  }
242 
243  err = ngx_socket_errno;
244 
245  if (err == NGX_EAGAIN || err == NGX_EINTR) {
247  "readv() not ready");
248  n = NGX_AGAIN;
249 
250  } else {
251  n = ngx_connection_error(c, err, "readv() failed");
252  break;
253  }
254 
255  } while (err == NGX_EINTR);
256 
257  rev->ready = 0;
258 
259  if (n == NGX_ERROR) {
260  c->read->error = 1;
261  }
262 
263  return n;
264 }
265 
266 #endif /* NGX_HAVE_KQUEUE */