|
|
1.1 misho 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
19: ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain)
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:
30: if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
31: ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
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:
92: ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
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
127: ngx_log_error(NGX_LOG_ALERT, c->log, 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) {
153: ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
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
176: ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain)
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:
220: ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
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) {
246: ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
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 */