xref: /unit/src/nxt_sendbuf.c (revision 0)
1*0Sigor@sysoev.ru 
2*0Sigor@sysoev.ru /*
3*0Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
4*0Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
5*0Sigor@sysoev.ru  */
6*0Sigor@sysoev.ru 
7*0Sigor@sysoev.ru #include <nxt_main.h>
8*0Sigor@sysoev.ru 
9*0Sigor@sysoev.ru 
10*0Sigor@sysoev.ru static nxt_bool_t nxt_sendbuf_copy(nxt_buf_mem_t *bm, nxt_buf_t *b,
11*0Sigor@sysoev.ru     size_t *copied);
12*0Sigor@sysoev.ru 
13*0Sigor@sysoev.ru 
14*0Sigor@sysoev.ru nxt_uint_t
15*0Sigor@sysoev.ru nxt_sendbuf_mem_coalesce(nxt_sendbuf_coalesce_t *sb)
16*0Sigor@sysoev.ru {
17*0Sigor@sysoev.ru     u_char      *last;
18*0Sigor@sysoev.ru     size_t      size, total;
19*0Sigor@sysoev.ru     nxt_buf_t   *b;
20*0Sigor@sysoev.ru     nxt_uint_t  n;
21*0Sigor@sysoev.ru 
22*0Sigor@sysoev.ru     total = sb->size;
23*0Sigor@sysoev.ru     last = NULL;
24*0Sigor@sysoev.ru     n = (nxt_uint_t) -1;
25*0Sigor@sysoev.ru 
26*0Sigor@sysoev.ru     for (b = sb->buf; b != NULL && total < sb->limit; b = b->next) {
27*0Sigor@sysoev.ru 
28*0Sigor@sysoev.ru         nxt_prefetch(b->next);
29*0Sigor@sysoev.ru 
30*0Sigor@sysoev.ru         if (nxt_buf_is_file(b)) {
31*0Sigor@sysoev.ru             break;
32*0Sigor@sysoev.ru         }
33*0Sigor@sysoev.ru 
34*0Sigor@sysoev.ru         if (nxt_buf_is_mem(b)) {
35*0Sigor@sysoev.ru 
36*0Sigor@sysoev.ru             size = b->mem.free - b->mem.pos;
37*0Sigor@sysoev.ru 
38*0Sigor@sysoev.ru             if (size != 0) {
39*0Sigor@sysoev.ru 
40*0Sigor@sysoev.ru                 if (total + size > sb->limit) {
41*0Sigor@sysoev.ru                     size = sb->limit - total;
42*0Sigor@sysoev.ru 
43*0Sigor@sysoev.ru                     if (size == 0) {
44*0Sigor@sysoev.ru                         break;
45*0Sigor@sysoev.ru                     }
46*0Sigor@sysoev.ru                 }
47*0Sigor@sysoev.ru 
48*0Sigor@sysoev.ru                 if (b->mem.pos != last) {
49*0Sigor@sysoev.ru 
50*0Sigor@sysoev.ru                     if (++n >= sb->nmax) {
51*0Sigor@sysoev.ru                         goto done;
52*0Sigor@sysoev.ru                     }
53*0Sigor@sysoev.ru 
54*0Sigor@sysoev.ru                     nxt_iobuf_set(&sb->iobuf[n], b->mem.pos, size);
55*0Sigor@sysoev.ru 
56*0Sigor@sysoev.ru                 } else {
57*0Sigor@sysoev.ru                     nxt_iobuf_add(&sb->iobuf[n], size);
58*0Sigor@sysoev.ru                 }
59*0Sigor@sysoev.ru 
60*0Sigor@sysoev.ru                 nxt_thread_log_debug("sendbuf: %ui, %p, %uz", n,
61*0Sigor@sysoev.ru                                      nxt_iobuf_data(&sb->iobuf[n]),
62*0Sigor@sysoev.ru                                      nxt_iobuf_size(&sb->iobuf[n]));
63*0Sigor@sysoev.ru 
64*0Sigor@sysoev.ru                 total += size;
65*0Sigor@sysoev.ru                 last = b->mem.pos + size;
66*0Sigor@sysoev.ru             }
67*0Sigor@sysoev.ru 
68*0Sigor@sysoev.ru         } else {
69*0Sigor@sysoev.ru             sb->sync = 1;
70*0Sigor@sysoev.ru             sb->last |= nxt_buf_is_last(b);
71*0Sigor@sysoev.ru         }
72*0Sigor@sysoev.ru     }
73*0Sigor@sysoev.ru 
74*0Sigor@sysoev.ru     n++;
75*0Sigor@sysoev.ru 
76*0Sigor@sysoev.ru done:
77*0Sigor@sysoev.ru 
78*0Sigor@sysoev.ru     sb->buf = b;
79*0Sigor@sysoev.ru     sb->size = total;
80*0Sigor@sysoev.ru 
81*0Sigor@sysoev.ru     return n;
82*0Sigor@sysoev.ru }
83*0Sigor@sysoev.ru 
84*0Sigor@sysoev.ru 
85*0Sigor@sysoev.ru size_t
86*0Sigor@sysoev.ru nxt_sendbuf_file_coalesce(nxt_sendbuf_coalesce_t *sb)
87*0Sigor@sysoev.ru {
88*0Sigor@sysoev.ru     size_t     file_start, total;
89*0Sigor@sysoev.ru     nxt_fd_t   fd;
90*0Sigor@sysoev.ru     nxt_off_t  size, last;
91*0Sigor@sysoev.ru     nxt_buf_t  *b;
92*0Sigor@sysoev.ru 
93*0Sigor@sysoev.ru     b = sb->buf;
94*0Sigor@sysoev.ru     fd = b->file->fd;
95*0Sigor@sysoev.ru 
96*0Sigor@sysoev.ru     total = sb->size;
97*0Sigor@sysoev.ru 
98*0Sigor@sysoev.ru     for ( ;; ) {
99*0Sigor@sysoev.ru 
100*0Sigor@sysoev.ru         nxt_prefetch(b->next);
101*0Sigor@sysoev.ru 
102*0Sigor@sysoev.ru         size = b->file_end - b->file_pos;
103*0Sigor@sysoev.ru 
104*0Sigor@sysoev.ru         if (total + size >= sb->limit) {
105*0Sigor@sysoev.ru             total = sb->limit;
106*0Sigor@sysoev.ru             break;
107*0Sigor@sysoev.ru         }
108*0Sigor@sysoev.ru 
109*0Sigor@sysoev.ru         total += size;
110*0Sigor@sysoev.ru         last = b->file_pos + size;
111*0Sigor@sysoev.ru 
112*0Sigor@sysoev.ru         b = b->next;
113*0Sigor@sysoev.ru 
114*0Sigor@sysoev.ru         if (b == NULL || !nxt_buf_is_file(b)) {
115*0Sigor@sysoev.ru             break;
116*0Sigor@sysoev.ru         }
117*0Sigor@sysoev.ru 
118*0Sigor@sysoev.ru         if (b->file_pos != last || b->file->fd != fd) {
119*0Sigor@sysoev.ru             break;
120*0Sigor@sysoev.ru         }
121*0Sigor@sysoev.ru     }
122*0Sigor@sysoev.ru 
123*0Sigor@sysoev.ru     sb->buf = b;
124*0Sigor@sysoev.ru 
125*0Sigor@sysoev.ru     file_start = sb->size;
126*0Sigor@sysoev.ru     sb->size = total;
127*0Sigor@sysoev.ru 
128*0Sigor@sysoev.ru     return total - file_start;
129*0Sigor@sysoev.ru }
130*0Sigor@sysoev.ru 
131*0Sigor@sysoev.ru 
132*0Sigor@sysoev.ru ssize_t
133*0Sigor@sysoev.ru nxt_sendbuf_copy_coalesce(nxt_event_conn_t *c, nxt_buf_mem_t *bm,
134*0Sigor@sysoev.ru     nxt_buf_t *b, size_t limit)
135*0Sigor@sysoev.ru {
136*0Sigor@sysoev.ru     size_t      size, bsize, copied;
137*0Sigor@sysoev.ru     ssize_t     n;
138*0Sigor@sysoev.ru     nxt_bool_t  flush;
139*0Sigor@sysoev.ru 
140*0Sigor@sysoev.ru     size = nxt_buf_mem_used_size(&b->mem);
141*0Sigor@sysoev.ru     bsize = nxt_buf_mem_size(bm);
142*0Sigor@sysoev.ru 
143*0Sigor@sysoev.ru     if (bsize != 0) {
144*0Sigor@sysoev.ru 
145*0Sigor@sysoev.ru         if (size > bsize && bm->pos == bm->free) {
146*0Sigor@sysoev.ru             /*
147*0Sigor@sysoev.ru              * A data buffer size is larger than the internal
148*0Sigor@sysoev.ru              * buffer size and the internal buffer is empty.
149*0Sigor@sysoev.ru              */
150*0Sigor@sysoev.ru             goto no_buffer;
151*0Sigor@sysoev.ru         }
152*0Sigor@sysoev.ru 
153*0Sigor@sysoev.ru         if (bm->pos == NULL) {
154*0Sigor@sysoev.ru             bm->pos = nxt_malloc(bsize);
155*0Sigor@sysoev.ru             if (nxt_slow_path(bm->pos == NULL)) {
156*0Sigor@sysoev.ru                 return NXT_ERROR;
157*0Sigor@sysoev.ru             }
158*0Sigor@sysoev.ru 
159*0Sigor@sysoev.ru             bm->start = bm->pos;
160*0Sigor@sysoev.ru             bm->free = bm->pos;
161*0Sigor@sysoev.ru             bm->end += (uintptr_t) bm->pos;
162*0Sigor@sysoev.ru         }
163*0Sigor@sysoev.ru 
164*0Sigor@sysoev.ru         copied = 0;
165*0Sigor@sysoev.ru 
166*0Sigor@sysoev.ru         flush = nxt_sendbuf_copy(bm, b, &copied);
167*0Sigor@sysoev.ru 
168*0Sigor@sysoev.ru         nxt_log_debug(c->socket.log, "sendbuf copy:%uz fl:%b", copied, flush);
169*0Sigor@sysoev.ru 
170*0Sigor@sysoev.ru         if (flush == 0) {
171*0Sigor@sysoev.ru             return copied;
172*0Sigor@sysoev.ru         }
173*0Sigor@sysoev.ru 
174*0Sigor@sysoev.ru         size = nxt_buf_mem_used_size(bm);
175*0Sigor@sysoev.ru 
176*0Sigor@sysoev.ru         if (size == 0 && nxt_buf_is_sync(b)) {
177*0Sigor@sysoev.ru             goto done;
178*0Sigor@sysoev.ru         }
179*0Sigor@sysoev.ru 
180*0Sigor@sysoev.ru         n = c->io->send(c, bm->pos, nxt_min(size, limit));
181*0Sigor@sysoev.ru 
182*0Sigor@sysoev.ru         nxt_log_debug(c->socket.log, "sendbuf sent:%z", n);
183*0Sigor@sysoev.ru 
184*0Sigor@sysoev.ru         if (n > 0) {
185*0Sigor@sysoev.ru             bm->pos += n;
186*0Sigor@sysoev.ru 
187*0Sigor@sysoev.ru             if (bm->pos == bm->free) {
188*0Sigor@sysoev.ru                 bm->pos = bm->start;
189*0Sigor@sysoev.ru                 bm->free = bm->start;
190*0Sigor@sysoev.ru             }
191*0Sigor@sysoev.ru 
192*0Sigor@sysoev.ru             n = 0;
193*0Sigor@sysoev.ru         }
194*0Sigor@sysoev.ru 
195*0Sigor@sysoev.ru         return (copied != 0) ? (ssize_t) copied : n;
196*0Sigor@sysoev.ru     }
197*0Sigor@sysoev.ru 
198*0Sigor@sysoev.ru     /* No internal buffering. */
199*0Sigor@sysoev.ru 
200*0Sigor@sysoev.ru     if (size == 0 && nxt_buf_is_sync(b)) {
201*0Sigor@sysoev.ru         goto done;
202*0Sigor@sysoev.ru     }
203*0Sigor@sysoev.ru 
204*0Sigor@sysoev.ru no_buffer:
205*0Sigor@sysoev.ru 
206*0Sigor@sysoev.ru     return c->io->send(c, b->mem.pos, nxt_min(size, limit));
207*0Sigor@sysoev.ru 
208*0Sigor@sysoev.ru done:
209*0Sigor@sysoev.ru 
210*0Sigor@sysoev.ru     nxt_log_debug(c->socket.log, "sendbuf done");
211*0Sigor@sysoev.ru 
212*0Sigor@sysoev.ru     return 0;
213*0Sigor@sysoev.ru }
214*0Sigor@sysoev.ru 
215*0Sigor@sysoev.ru 
216*0Sigor@sysoev.ru static nxt_bool_t
217*0Sigor@sysoev.ru nxt_sendbuf_copy(nxt_buf_mem_t *bm, nxt_buf_t *b, size_t *copied)
218*0Sigor@sysoev.ru {
219*0Sigor@sysoev.ru     size_t      size, bsize;
220*0Sigor@sysoev.ru     nxt_bool_t  flush;
221*0Sigor@sysoev.ru 
222*0Sigor@sysoev.ru     flush = 0;
223*0Sigor@sysoev.ru 
224*0Sigor@sysoev.ru     do {
225*0Sigor@sysoev.ru         nxt_prefetch(b->next);
226*0Sigor@sysoev.ru 
227*0Sigor@sysoev.ru         if (nxt_buf_is_mem(b)) {
228*0Sigor@sysoev.ru             bsize = bm->end - bm->free;
229*0Sigor@sysoev.ru             size = b->mem.free - b->mem.pos;
230*0Sigor@sysoev.ru             size = nxt_min(size, bsize);
231*0Sigor@sysoev.ru 
232*0Sigor@sysoev.ru             nxt_memcpy(bm->free, b->mem.pos, size);
233*0Sigor@sysoev.ru 
234*0Sigor@sysoev.ru             *copied += size;
235*0Sigor@sysoev.ru             bm->free += size;
236*0Sigor@sysoev.ru 
237*0Sigor@sysoev.ru             if (bm->free == bm->end) {
238*0Sigor@sysoev.ru                 return 1;
239*0Sigor@sysoev.ru             }
240*0Sigor@sysoev.ru         }
241*0Sigor@sysoev.ru 
242*0Sigor@sysoev.ru         flush |= nxt_buf_is_flush(b) || nxt_buf_is_last(b);
243*0Sigor@sysoev.ru 
244*0Sigor@sysoev.ru         b = b->next;
245*0Sigor@sysoev.ru 
246*0Sigor@sysoev.ru     } while (b != NULL);
247*0Sigor@sysoev.ru 
248*0Sigor@sysoev.ru     return flush;
249*0Sigor@sysoev.ru }
250*0Sigor@sysoev.ru 
251*0Sigor@sysoev.ru 
252*0Sigor@sysoev.ru nxt_buf_t *
253*0Sigor@sysoev.ru nxt_sendbuf_update(nxt_buf_t *b, size_t sent)
254*0Sigor@sysoev.ru {
255*0Sigor@sysoev.ru     size_t  size;
256*0Sigor@sysoev.ru 
257*0Sigor@sysoev.ru     while (b != NULL) {
258*0Sigor@sysoev.ru 
259*0Sigor@sysoev.ru         nxt_prefetch(b->next);
260*0Sigor@sysoev.ru 
261*0Sigor@sysoev.ru         if (!nxt_buf_is_sync(b)) {
262*0Sigor@sysoev.ru 
263*0Sigor@sysoev.ru             size = nxt_buf_used_size(b);
264*0Sigor@sysoev.ru 
265*0Sigor@sysoev.ru             if (size != 0) {
266*0Sigor@sysoev.ru 
267*0Sigor@sysoev.ru                 if (sent == 0) {
268*0Sigor@sysoev.ru                     break;
269*0Sigor@sysoev.ru                 }
270*0Sigor@sysoev.ru 
271*0Sigor@sysoev.ru                 if (sent < size) {
272*0Sigor@sysoev.ru 
273*0Sigor@sysoev.ru                     if (nxt_buf_is_mem(b)) {
274*0Sigor@sysoev.ru                         b->mem.pos += sent;
275*0Sigor@sysoev.ru                     }
276*0Sigor@sysoev.ru 
277*0Sigor@sysoev.ru                     if (nxt_buf_is_file(b)) {
278*0Sigor@sysoev.ru                         b->file_pos += sent;
279*0Sigor@sysoev.ru                     }
280*0Sigor@sysoev.ru 
281*0Sigor@sysoev.ru                     break;
282*0Sigor@sysoev.ru                 }
283*0Sigor@sysoev.ru 
284*0Sigor@sysoev.ru                 /* b->mem.free is NULL in file-only buffer. */
285*0Sigor@sysoev.ru                 b->mem.pos = b->mem.free;
286*0Sigor@sysoev.ru 
287*0Sigor@sysoev.ru                 if (nxt_buf_is_file(b)) {
288*0Sigor@sysoev.ru                     b->file_pos = b->file_end;
289*0Sigor@sysoev.ru                 }
290*0Sigor@sysoev.ru 
291*0Sigor@sysoev.ru                 sent -= size;
292*0Sigor@sysoev.ru             }
293*0Sigor@sysoev.ru         }
294*0Sigor@sysoev.ru 
295*0Sigor@sysoev.ru         b = b->next;
296*0Sigor@sysoev.ru     }
297*0Sigor@sysoev.ru 
298*0Sigor@sysoev.ru     return b;
299*0Sigor@sysoev.ru }
300*0Sigor@sysoev.ru 
301*0Sigor@sysoev.ru 
302*0Sigor@sysoev.ru nxt_buf_t *
303*0Sigor@sysoev.ru nxt_sendbuf_completion(nxt_thread_t *thr, nxt_work_queue_t *wq, nxt_buf_t *b,
304*0Sigor@sysoev.ru     size_t sent)
305*0Sigor@sysoev.ru {
306*0Sigor@sysoev.ru     size_t  size;
307*0Sigor@sysoev.ru 
308*0Sigor@sysoev.ru     while (b != NULL) {
309*0Sigor@sysoev.ru 
310*0Sigor@sysoev.ru         nxt_prefetch(b->next);
311*0Sigor@sysoev.ru 
312*0Sigor@sysoev.ru         if (!nxt_buf_is_sync(b)) {
313*0Sigor@sysoev.ru 
314*0Sigor@sysoev.ru             size = nxt_buf_used_size(b);
315*0Sigor@sysoev.ru 
316*0Sigor@sysoev.ru             if (size != 0) {
317*0Sigor@sysoev.ru 
318*0Sigor@sysoev.ru                 if (sent == 0) {
319*0Sigor@sysoev.ru                     break;
320*0Sigor@sysoev.ru                 }
321*0Sigor@sysoev.ru 
322*0Sigor@sysoev.ru                 if (sent < size) {
323*0Sigor@sysoev.ru 
324*0Sigor@sysoev.ru                     if (nxt_buf_is_mem(b)) {
325*0Sigor@sysoev.ru                         b->mem.pos += sent;
326*0Sigor@sysoev.ru                     }
327*0Sigor@sysoev.ru 
328*0Sigor@sysoev.ru                     if (nxt_buf_is_file(b)) {
329*0Sigor@sysoev.ru                         b->file_pos += sent;
330*0Sigor@sysoev.ru                     }
331*0Sigor@sysoev.ru 
332*0Sigor@sysoev.ru                     break;
333*0Sigor@sysoev.ru                 }
334*0Sigor@sysoev.ru 
335*0Sigor@sysoev.ru                 /* b->mem.free is NULL in file-only buffer. */
336*0Sigor@sysoev.ru                 b->mem.pos = b->mem.free;
337*0Sigor@sysoev.ru 
338*0Sigor@sysoev.ru                 if (nxt_buf_is_file(b)) {
339*0Sigor@sysoev.ru                     b->file_pos = b->file_end;
340*0Sigor@sysoev.ru                 }
341*0Sigor@sysoev.ru 
342*0Sigor@sysoev.ru                 sent -= size;
343*0Sigor@sysoev.ru             }
344*0Sigor@sysoev.ru         }
345*0Sigor@sysoev.ru 
346*0Sigor@sysoev.ru         nxt_thread_work_queue_add(thr, wq, b->completion_handler,
347*0Sigor@sysoev.ru                                   b, b->parent, thr->log);
348*0Sigor@sysoev.ru 
349*0Sigor@sysoev.ru         b = b->next;
350*0Sigor@sysoev.ru     }
351*0Sigor@sysoev.ru 
352*0Sigor@sysoev.ru     return b;
353*0Sigor@sysoev.ru }
354