upstream nginx-0.7.31
[nginx.git] / nginx / src / os / unix / ngx_writev_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 #if (IOV_MAX > 64)
13 #define NGX_IOVS  64
14 #else
15 #define NGX_IOVS  IOV_MAX
16 #endif
17
18
19 ngx_chain_t *
20 ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
21 {
22     u_char        *prev;
23     ssize_t        n, size, sent;
24     off_t          send, prev_send;
25     ngx_uint_t     eintr, complete;
26     ngx_err_t      err;
27     ngx_array_t    vec;
28     ngx_chain_t   *cl;
29     ngx_event_t   *wev;
30     struct iovec  *iov, iovs[NGX_IOVS];
31
32     wev = c->write;
33
34     if (!wev->ready) {
35         return in;
36     }
37
38 #if (NGX_HAVE_KQUEUE)
39
40     if ((ngx_event_flags & NGX_USE_KQUEUE_EVENT) && wev->pending_eof) {
41         (void) ngx_connection_error(c, wev->kq_errno,
42                                "kevent() reported about an closed connection");
43         wev->error = 1;
44         return NGX_CHAIN_ERROR;
45     }
46
47 #endif
48
49     /* the maximum limit size is the maximum size_t value - the page size */
50
51     if (limit == 0 || limit > (off_t) (NGX_MAX_SIZE_T_VALUE - ngx_pagesize)) {
52         limit = NGX_MAX_SIZE_T_VALUE - ngx_pagesize;
53     }
54
55     send = 0;
56     complete = 0;
57
58     vec.elts = iovs;
59     vec.size = sizeof(struct iovec);
60     vec.nalloc = NGX_IOVS;
61     vec.pool = c->pool;
62
63     for ( ;; ) {
64         prev = NULL;
65         iov = NULL;
66         eintr = 0;
67         prev_send = send;
68
69         vec.nelts = 0;
70
71         /* create the iovec and coalesce the neighbouring bufs */
72
73         for (cl = in; cl && vec.nelts < IOV_MAX && send < limit; cl = cl->next)
74         {
75             if (ngx_buf_special(cl->buf)) {
76                 continue;
77             }
78
79 #if 1
80             if (!ngx_buf_in_memory(cl->buf)) {
81                 ngx_debug_point();
82             }
83 #endif
84
85             size = cl->buf->last - cl->buf->pos;
86
87             if (send + size > limit) {
88                 size = (ssize_t) (limit - send);
89             }
90
91             if (prev == cl->buf->pos) {
92                 iov->iov_len += size;
93
94             } else {
95                 iov = ngx_array_push(&vec);
96                 if (iov == NULL) {
97                     return NGX_CHAIN_ERROR;
98                 }
99
100                 iov->iov_base = (void *) cl->buf->pos;
101                 iov->iov_len = size;
102             }
103
104             prev = cl->buf->pos + size;
105             send += size;
106         }
107
108         n = writev(c->fd, vec.elts, vec.nelts);
109
110         if (n == -1) {
111             err = ngx_errno;
112
113             if (err == NGX_EAGAIN || err == NGX_EINTR) {
114                 if (err == NGX_EINTR) {
115                     eintr = 1;
116                 }
117
118                 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
119                                "writev() not ready");
120
121             } else {
122                 wev->error = 1;
123                 (void) ngx_connection_error(c, err, "writev() failed");
124                 return NGX_CHAIN_ERROR;
125             }
126         }
127
128         sent = n > 0 ? n : 0;
129
130         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "writev: %z", sent);
131
132         if (send - prev_send == sent) {
133             complete = 1;
134         }
135
136         c->sent += sent;
137
138         for (cl = in; cl; cl = cl->next) {
139
140             if (ngx_buf_special(cl->buf)) {
141                 continue;
142             }
143
144             if (sent == 0) {
145                 break;
146             }
147
148             size = cl->buf->last - cl->buf->pos;
149
150             if (sent >= size) {
151                 sent -= size;
152                 cl->buf->pos = cl->buf->last;
153
154                 continue;
155             }
156
157             cl->buf->pos += sent;
158
159             break;
160         }
161
162         if (eintr) {
163             continue;
164         }
165
166         if (!complete) {
167             wev->ready = 0;
168             return cl;
169         }
170
171         if (send >= limit || cl == NULL) {
172             return cl;
173         }
174
175         in = cl;
176     }
177 }