upstream nginx-0.7.31
[nginx.git] / nginx / src / os / unix / ngx_solaris_sendfilev_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 (NGX_TEST_BUILD_SOLARIS_SENDFILEV)
13
14 /* Solaris declarations */
15
16 typedef struct sendfilevec {
17     int     sfv_fd;
18     u_int   sfv_flag;
19     off_t   sfv_off;
20     size_t  sfv_len;
21 } sendfilevec_t;
22
23 #define SFV_FD_SELF  -2
24
25 static ssize_t sendfilev(int fd, const struct sendfilevec *vec,
26     int sfvcnt, size_t *xferred)
27 {
28     return -1;
29 }
30
31 #endif
32
33
34 #if (IOV_MAX > 64)
35 #define NGX_SENDFILEVECS  64
36 #else
37 #define NGX_SENDFILEVECS  IOV_MAX
38 #endif
39
40
41
42 ngx_chain_t *
43 ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
44 {
45     int             fd;
46     u_char         *prev;
47     off_t           size, send, prev_send, aligned, fprev;
48     size_t          sent;
49     ssize_t         n;
50     ngx_int_t       eintr, complete;
51     ngx_err_t       err;
52     sendfilevec_t  *sfv, sfvs[NGX_SENDFILEVECS];
53     ngx_array_t     vec;
54     ngx_event_t    *wev;
55     ngx_chain_t    *cl;
56
57     wev = c->write;
58
59     if (!wev->ready) {
60         return in;
61     }
62
63     if (!c->sendfile) {
64         return ngx_writev_chain(c, in, limit);
65     }
66
67
68     /* the maximum limit size is the maximum size_t value - the page size */
69
70     if (limit == 0 || limit > (off_t) (NGX_MAX_SIZE_T_VALUE - ngx_pagesize)) {
71         limit = NGX_MAX_SIZE_T_VALUE - ngx_pagesize;
72     }
73
74
75     send = 0;
76     complete = 0;
77
78     vec.elts = sfvs;
79     vec.size = sizeof(sendfilevec_t);
80     vec.nalloc = NGX_SENDFILEVECS;
81     vec.pool = c->pool;
82
83     for ( ;; ) {
84         fd = SFV_FD_SELF;
85         prev = NULL;
86         fprev = 0;
87         sfv = NULL;
88         eintr = 0;
89         sent = 0;
90         prev_send = send;
91
92         vec.nelts = 0;
93
94         /* create the sendfilevec and coalesce the neighbouring bufs */
95
96         for (cl = in; cl && vec.nelts < IOV_MAX && send < limit; cl = cl->next)
97         {
98             if (ngx_buf_special(cl->buf)) {
99                 continue;
100             }
101
102             if (ngx_buf_in_memory_only(cl->buf)) {
103                 fd = SFV_FD_SELF;
104
105                 size = cl->buf->last - cl->buf->pos;
106
107                 if (send + size > limit) {
108                     size = limit - send;
109                 }
110
111                 if (prev == cl->buf->pos) {
112                     sfv->sfv_len += (size_t) size;
113
114                 } else {
115                     sfv = ngx_array_push(&vec);
116                     if (sfv == NULL) {
117                         return NGX_CHAIN_ERROR;
118                     }
119
120                     sfv->sfv_fd = SFV_FD_SELF;
121                     sfv->sfv_flag = 0;
122                     sfv->sfv_off = (off_t) (uintptr_t) cl->buf->pos;
123                     sfv->sfv_len = (size_t) size;
124                 }
125
126                 prev = cl->buf->pos + (size_t) size;
127                 send += size;
128
129             } else {
130                 prev = NULL;
131
132                 size = cl->buf->file_last - cl->buf->file_pos;
133
134                 if (send + size > limit) {
135                     size = limit - send;
136
137                     aligned = (cl->buf->file_pos + size + ngx_pagesize - 1)
138                                & ~((off_t) ngx_pagesize - 1);
139
140                     if (aligned <= cl->buf->file_last) {
141                         size = aligned - cl->buf->file_pos;
142                     }
143                 }
144
145                 if (fd == cl->buf->file->fd && fprev == cl->buf->file_pos) {
146                     sfv->sfv_len += (size_t) size;
147
148                 } else {
149                     sfv = ngx_array_push(&vec);
150                     if (sfv == NULL) {
151                         return NGX_CHAIN_ERROR;
152                     }
153
154                     fd = cl->buf->file->fd;
155                     sfv->sfv_fd = fd;
156                     sfv->sfv_flag = 0;
157                     sfv->sfv_off = cl->buf->file_pos;
158                     sfv->sfv_len = (size_t) size;
159                 }
160
161                 fprev = cl->buf->file_pos + size;
162                 send += size;
163             }
164         }
165
166         n = sendfilev(c->fd, vec.elts, vec.nelts, &sent);
167
168         if (n == -1) {
169             err = ngx_errno;
170
171             if (err == NGX_EAGAIN || err == NGX_EINTR) {
172                 if (err == NGX_EINTR) {
173                     eintr = 1;
174                 }
175
176                 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, err,
177                               "sendfilev() sent only %uz bytes", sent);
178
179             } else {
180                 wev->error = 1;
181                 ngx_connection_error(c, err, "sendfilev() failed");
182                 return NGX_CHAIN_ERROR;
183             }
184         }
185
186         ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
187                        "sendfilev: %z %z", n, sent);
188
189         if (send - prev_send == (off_t) sent) {
190             complete = 1;
191         }
192
193         c->sent += sent;
194
195         for (cl = in; cl; cl = cl->next) {
196
197             if (ngx_buf_special(cl->buf)) {
198                 continue;
199             }
200
201             if (sent == 0) {
202                 break;
203             }
204
205             size = ngx_buf_size(cl->buf);
206
207             if ((off_t) sent >= size) {
208                 sent = (size_t) ((off_t) sent - size);
209
210                 if (ngx_buf_in_memory(cl->buf)) {
211                     cl->buf->pos = cl->buf->last;
212                 }
213
214                 if (cl->buf->in_file) {
215                     cl->buf->file_pos = cl->buf->file_last;
216                 }
217
218                 continue;
219             }
220
221             if (ngx_buf_in_memory(cl->buf)) {
222                 cl->buf->pos += sent;
223             }
224
225             if (cl->buf->in_file) {
226                 cl->buf->file_pos += sent;
227             }
228
229             break;
230         }
231
232         if (eintr) {
233             continue;
234         }
235
236         if (!complete) {
237             wev->ready = 0;
238             return cl;
239         }
240
241         if (send >= limit || cl == NULL) {
242             return cl;
243         }
244
245         in = cl;
246     }
247 }