~ubuntu-branches/ubuntu/wily/nginx/wily

« back to all changes in this revision

Viewing changes to src/os/unix/ngx_darwin_sendfile_chain.c

  • Committer: Package Import Robot
  • Author(s): Thomas Ward
  • Date: 2015-07-22 11:39:44 UTC
  • mfrom: (4.3.25 sid)
  • Revision ID: package-import@ubuntu.com-20150722113944-lrmrnya8cg40kz4m
Tags: 1.9.3-1ubuntu1
* Merge from Debian.  Remaining changes: (LP: #1476811)
  - debian/patches/ubuntu-branding.patch: add Ubuntu branding (refreshed)
  - d/{control,rules,nginx-core.*}: add new binary package for main,
    nginx-core, which contains only source-tarball-included modules
    and no third-party modules.
  - debian/tests/control: add nginx-core test.
  - debian/control: drop luajit from Build-Depends as it is in universe.
  - debian/apport/source_nginx.py: Add apport hooks for additional bug
    information gathering.
  - debian/nginx-common.install: Add install rule for apport hooks.

Show diffs side-by-side

added added

removed removed

Lines of Context:
13
13
/*
14
14
 * It seems that Darwin 9.4 (Mac OS X 1.5) sendfile() has the same
15
15
 * old bug as early FreeBSD sendfile() syscall:
16
 
 * http://www.freebsd.org/cgi/query-pr.cgi?pr=33771
 
16
 * http://bugs.freebsd.org/33771
17
17
 *
18
18
 * Besides sendfile() has another bug: if one calls sendfile()
19
19
 * with both a header and a trailer, then sendfile() ignores a file part
27
27
 */
28
28
 
29
29
 
30
 
#if (IOV_MAX > 64)
31
 
#define NGX_HEADERS   64
32
 
#define NGX_TRAILERS  64
33
 
#else
34
 
#define NGX_HEADERS   IOV_MAX
35
 
#define NGX_TRAILERS  IOV_MAX
36
 
#endif
37
 
 
38
 
 
39
30
ngx_chain_t *
40
31
ngx_darwin_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
41
32
{
42
33
    int              rc;
43
 
    u_char          *prev;
44
 
    off_t            size, send, prev_send, aligned, sent, fprev;
45
 
    off_t            header_size, file_size;
46
 
    ngx_uint_t       eintr, complete;
 
34
    off_t            send, prev_send, sent;
 
35
    off_t            file_size;
 
36
    ssize_t          n;
 
37
    ngx_uint_t       eintr;
47
38
    ngx_err_t        err;
48
39
    ngx_buf_t       *file;
49
 
    ngx_array_t      header, trailer;
50
40
    ngx_event_t     *wev;
51
41
    ngx_chain_t     *cl;
 
42
    ngx_iovec_t      header, trailer;
52
43
    struct sf_hdtr   hdtr;
53
 
    struct iovec    *iov, headers[NGX_HEADERS], trailers[NGX_TRAILERS];
 
44
    struct iovec     headers[NGX_IOVS_PREALLOCATE];
 
45
    struct iovec     trailers[NGX_IOVS_PREALLOCATE];
54
46
 
55
47
    wev = c->write;
56
48
 
77
69
 
78
70
    send = 0;
79
71
 
80
 
    header.elts = headers;
81
 
    header.size = sizeof(struct iovec);
82
 
    header.nalloc = NGX_HEADERS;
83
 
    header.pool = c->pool;
 
72
    header.iovs = headers;
 
73
    header.nalloc = NGX_IOVS_PREALLOCATE;
84
74
 
85
 
    trailer.elts = trailers;
86
 
    trailer.size = sizeof(struct iovec);
87
 
    trailer.nalloc = NGX_TRAILERS;
88
 
    trailer.pool = c->pool;
 
75
    trailer.iovs = trailers;
 
76
    trailer.nalloc = NGX_IOVS_PREALLOCATE;
89
77
 
90
78
    for ( ;; ) {
91
 
        file = NULL;
92
 
        file_size = 0;
93
 
        header_size = 0;
94
79
        eintr = 0;
95
 
        complete = 0;
96
80
        prev_send = send;
97
81
 
98
 
        header.nelts = 0;
99
 
        trailer.nelts = 0;
100
 
 
101
82
        /* create the header iovec and coalesce the neighbouring bufs */
102
83
 
103
 
        prev = NULL;
104
 
        iov = NULL;
105
 
 
106
 
        for (cl = in; cl && send < limit; cl = cl->next) {
107
 
 
108
 
            if (ngx_buf_special(cl->buf)) {
109
 
                continue;
110
 
            }
111
 
 
112
 
            if (!ngx_buf_in_memory_only(cl->buf)) {
113
 
                break;
114
 
            }
115
 
 
116
 
            size = cl->buf->last - cl->buf->pos;
117
 
 
118
 
            if (send + size > limit) {
119
 
                size = limit - send;
120
 
            }
121
 
 
122
 
            if (prev == cl->buf->pos) {
123
 
                iov->iov_len += (size_t) size;
124
 
 
125
 
            } else {
126
 
                if (header.nelts >= IOV_MAX) {
127
 
                    break;
128
 
                }
129
 
 
130
 
                iov = ngx_array_push(&header);
131
 
                if (iov == NULL) {
132
 
                    return NGX_CHAIN_ERROR;
133
 
                }
134
 
 
135
 
                iov->iov_base = (void *) cl->buf->pos;
136
 
                iov->iov_len = (size_t) size;
137
 
            }
138
 
 
139
 
            prev = cl->buf->pos + (size_t) size;
140
 
            header_size += size;
141
 
            send += size;
 
84
        cl = ngx_output_chain_to_iovec(&header, in, limit - send, c->log);
 
85
 
 
86
        if (cl == NGX_CHAIN_ERROR) {
 
87
            return NGX_CHAIN_ERROR;
142
88
        }
143
89
 
 
90
        send += header.size;
144
91
 
145
92
        if (cl && cl->buf->in_file && send < limit) {
146
93
            file = cl->buf;
147
94
 
148
95
            /* coalesce the neighbouring file bufs */
149
96
 
150
 
            do {
151
 
                size = cl->buf->file_last - cl->buf->file_pos;
152
 
 
153
 
                if (send + size > limit) {
154
 
                    size = limit - send;
155
 
 
156
 
                    aligned = (cl->buf->file_pos + size + ngx_pagesize - 1)
157
 
                               & ~((off_t) ngx_pagesize - 1);
158
 
 
159
 
                    if (aligned <= cl->buf->file_last) {
160
 
                        size = aligned - cl->buf->file_pos;
161
 
                    }
162
 
                }
163
 
 
164
 
                file_size += size;
165
 
                send += size;
166
 
                fprev = cl->buf->file_pos + size;
167
 
                cl = cl->next;
168
 
 
169
 
            } while (cl
170
 
                     && cl->buf->in_file
171
 
                     && send < limit
172
 
                     && file->file->fd == cl->buf->file->fd
173
 
                     && fprev == cl->buf->file_pos);
174
 
        }
175
 
 
176
 
        if (file && header.nelts == 0) {
177
 
 
178
 
            /* create the trailer iovec and coalesce the neighbouring bufs */
179
 
 
180
 
            prev = NULL;
181
 
            iov = NULL;
182
 
 
183
 
            while (cl && send < limit) {
184
 
 
185
 
                if (ngx_buf_special(cl->buf)) {
186
 
                    cl = cl->next;
187
 
                    continue;
188
 
                }
189
 
 
190
 
                if (!ngx_buf_in_memory_only(cl->buf)) {
191
 
                    break;
192
 
                }
193
 
 
194
 
                size = cl->buf->last - cl->buf->pos;
195
 
 
196
 
                if (send + size > limit) {
197
 
                    size = limit - send;
198
 
                }
199
 
 
200
 
                if (prev == cl->buf->pos) {
201
 
                    iov->iov_len += (size_t) size;
202
 
 
203
 
                } else {
204
 
                    if (trailer.nelts >= IOV_MAX) {
205
 
                        break;
206
 
                    }
207
 
 
208
 
                    iov = ngx_array_push(&trailer);
209
 
                    if (iov == NULL) {
210
 
                        return NGX_CHAIN_ERROR;
211
 
                    }
212
 
 
213
 
                    iov->iov_base = (void *) cl->buf->pos;
214
 
                    iov->iov_len = (size_t) size;
215
 
                }
216
 
 
217
 
                prev = cl->buf->pos + (size_t) size;
218
 
                send += size;
219
 
                cl = cl->next;
 
97
            file_size = ngx_chain_coalesce_file(&cl, limit - send);
 
98
 
 
99
            send += file_size;
 
100
 
 
101
            if (header.count == 0) {
 
102
 
 
103
                /*
 
104
                 * create the trailer iovec and coalesce the neighbouring bufs
 
105
                 */
 
106
 
 
107
                cl = ngx_output_chain_to_iovec(&trailer, cl, limit - send,
 
108
                                               c->log);
 
109
                if (cl == NGX_CHAIN_ERROR) {
 
110
                    return NGX_CHAIN_ERROR;
 
111
                }
 
112
 
 
113
                send += trailer.size;
 
114
 
 
115
            } else {
 
116
                trailer.count = 0;
220
117
            }
221
 
        }
222
 
 
223
 
        if (file) {
224
118
 
225
119
            /*
226
120
             * sendfile() returns EINVAL if sf_hdtr's count is 0,
227
121
             * but corresponding pointer is not NULL
228
122
             */
229
123
 
230
 
            hdtr.headers = header.nelts ? (struct iovec *) header.elts: NULL;
231
 
            hdtr.hdr_cnt = header.nelts;
232
 
            hdtr.trailers = trailer.nelts ? (struct iovec *) trailer.elts: NULL;
233
 
            hdtr.trl_cnt = trailer.nelts;
 
124
            hdtr.headers = header.count ? header.iovs : NULL;
 
125
            hdtr.hdr_cnt = header.count;
 
126
            hdtr.trailers = trailer.count ? trailer.iovs : NULL;
 
127
            hdtr.trl_cnt = trailer.count;
234
128
 
235
 
            sent = header_size + file_size;
 
129
            sent = header.size + file_size;
236
130
 
237
131
            ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
238
 
                           "sendfile: @%O %O h:%O",
239
 
                           file->file_pos, sent, header_size);
 
132
                           "sendfile: @%O %O h:%uz",
 
133
                           file->file_pos, sent, header.size);
240
134
 
241
135
            rc = sendfile(file->file->fd, c->fd, file->file_pos,
242
136
                          &sent, &hdtr, 0);
279
173
 
280
174
            ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
281
175
                           "sendfile: %d, @%O %O:%O",
282
 
                           rc, file->file_pos, sent, file_size + header_size);
 
176
                           rc, file->file_pos, sent, file_size + header.size);
283
177
 
284
178
        } else {
285
 
            rc = writev(c->fd, header.elts, header.nelts);
286
 
 
287
 
            ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
288
 
                           "writev: %d of %uz", rc, send);
289
 
 
290
 
            if (rc == -1) {
291
 
                err = ngx_errno;
292
 
 
293
 
                switch (err) {
294
 
                case NGX_EAGAIN:
295
 
                    break;
296
 
 
297
 
                case NGX_EINTR:
298
 
                    eintr = 1;
299
 
                    break;
300
 
 
301
 
                default:
302
 
                    wev->error = 1;
303
 
                    ngx_connection_error(c, err, "writev() failed");
304
 
                    return NGX_CHAIN_ERROR;
305
 
                }
306
 
 
307
 
                ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
308
 
                               "writev() not ready");
 
179
            n = ngx_writev(c, &header);
 
180
 
 
181
            if (n == NGX_ERROR) {
 
182
                return NGX_CHAIN_ERROR;
309
183
            }
310
184
 
311
 
            sent = rc > 0 ? rc : 0;
312
 
        }
313
 
 
314
 
        if (send - prev_send == sent) {
315
 
            complete = 1;
 
185
            sent = (n == NGX_AGAIN) ? 0 : n;
316
186
        }
317
187
 
318
188
        c->sent += sent;
319
189
 
320
 
        for ( /* void */ ; in; in = in->next) {
321
 
 
322
 
            if (ngx_buf_special(in->buf)) {
323
 
                continue;
324
 
            }
325
 
 
326
 
            if (sent == 0) {
327
 
                break;
328
 
            }
329
 
 
330
 
            size = ngx_buf_size(in->buf);
331
 
 
332
 
            if (sent >= size) {
333
 
                sent -= size;
334
 
 
335
 
                if (ngx_buf_in_memory(in->buf)) {
336
 
                    in->buf->pos = in->buf->last;
337
 
                }
338
 
 
339
 
                if (in->buf->in_file) {
340
 
                    in->buf->file_pos = in->buf->file_last;
341
 
                }
342
 
 
343
 
                continue;
344
 
            }
345
 
 
346
 
            if (ngx_buf_in_memory(in->buf)) {
347
 
                in->buf->pos += (size_t) sent;
348
 
            }
349
 
 
350
 
            if (in->buf->in_file) {
351
 
                in->buf->file_pos += sent;
352
 
            }
353
 
 
354
 
            break;
355
 
        }
 
190
        in = ngx_chain_update_sent(in, sent);
356
191
 
357
192
        if (eintr) {
 
193
            send = prev_send + sent;
358
194
            continue;
359
195
        }
360
196
 
361
 
        if (!complete) {
 
197
        if (send - prev_send != sent) {
362
198
            wev->ready = 0;
363
199
            return in;
364
200
        }