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