10Sigor@sysoev.ru
20Sigor@sysoev.ru /*
30Sigor@sysoev.ru * Copyright (C) Igor Sysoev
40Sigor@sysoev.ru * Copyright (C) NGINX, Inc.
50Sigor@sysoev.ru */
60Sigor@sysoev.ru
70Sigor@sysoev.ru #include <nxt_main.h>
80Sigor@sysoev.ru
90Sigor@sysoev.ru
100Sigor@sysoev.ru static nxt_bool_t nxt_sendbuf_copy(nxt_buf_mem_t *bm, nxt_buf_t *b,
110Sigor@sysoev.ru size_t *copied);
12*1269Sigor@sysoev.ru static nxt_buf_t *nxt_sendbuf_coalesce_completion(nxt_task_t *task,
13*1269Sigor@sysoev.ru nxt_work_queue_t *wq, nxt_buf_t *start);
140Sigor@sysoev.ru
150Sigor@sysoev.ru
160Sigor@sysoev.ru nxt_uint_t
nxt_sendbuf_mem_coalesce0(nxt_task_t * task,nxt_sendbuf_t * sb,struct iovec * iov,nxt_uint_t niov_max)1713Sigor@sysoev.ru nxt_sendbuf_mem_coalesce0(nxt_task_t *task, nxt_sendbuf_t *sb,
1813Sigor@sysoev.ru struct iovec *iov, nxt_uint_t niov_max)
1913Sigor@sysoev.ru {
2013Sigor@sysoev.ru u_char *last;
2113Sigor@sysoev.ru size_t size, total;
2213Sigor@sysoev.ru nxt_buf_t *b;
2313Sigor@sysoev.ru nxt_uint_t n;
2413Sigor@sysoev.ru
2513Sigor@sysoev.ru total = sb->size;
2613Sigor@sysoev.ru last = NULL;
2713Sigor@sysoev.ru n = (nxt_uint_t) -1;
2813Sigor@sysoev.ru
2913Sigor@sysoev.ru for (b = sb->buf; b != NULL && total < sb->limit; b = b->next) {
3013Sigor@sysoev.ru
3113Sigor@sysoev.ru nxt_prefetch(b->next);
3213Sigor@sysoev.ru
3313Sigor@sysoev.ru if (nxt_buf_is_file(b)) {
3413Sigor@sysoev.ru break;
3513Sigor@sysoev.ru }
3613Sigor@sysoev.ru
3713Sigor@sysoev.ru if (nxt_buf_is_mem(b)) {
3813Sigor@sysoev.ru
3913Sigor@sysoev.ru size = b->mem.free - b->mem.pos;
4013Sigor@sysoev.ru
4113Sigor@sysoev.ru if (size != 0) {
4213Sigor@sysoev.ru
4313Sigor@sysoev.ru if (total + size > sb->limit) {
4413Sigor@sysoev.ru size = sb->limit - total;
4513Sigor@sysoev.ru
4613Sigor@sysoev.ru if (size == 0) {
4713Sigor@sysoev.ru break;
4813Sigor@sysoev.ru }
4913Sigor@sysoev.ru }
5013Sigor@sysoev.ru
5113Sigor@sysoev.ru if (b->mem.pos != last) {
5213Sigor@sysoev.ru
5313Sigor@sysoev.ru if (++n >= niov_max) {
5413Sigor@sysoev.ru goto done;
5513Sigor@sysoev.ru }
5613Sigor@sysoev.ru
57521Szelenkov@nginx.com iov[n].iov_base = b->mem.pos;
5813Sigor@sysoev.ru iov[n].iov_len = size;
5913Sigor@sysoev.ru
6013Sigor@sysoev.ru } else {
6113Sigor@sysoev.ru iov[n].iov_len += size;
6213Sigor@sysoev.ru }
6313Sigor@sysoev.ru
6413Sigor@sysoev.ru nxt_debug(task, "sendbuf: %ui, %p, %uz",
6513Sigor@sysoev.ru n, iov[n].iov_base, iov[n].iov_len);
6613Sigor@sysoev.ru
6713Sigor@sysoev.ru total += size;
6813Sigor@sysoev.ru last = b->mem.pos + size;
6913Sigor@sysoev.ru }
7013Sigor@sysoev.ru
7113Sigor@sysoev.ru } else {
7213Sigor@sysoev.ru sb->sync = 1;
7313Sigor@sysoev.ru sb->last |= nxt_buf_is_last(b);
7413Sigor@sysoev.ru }
7513Sigor@sysoev.ru }
7613Sigor@sysoev.ru
7713Sigor@sysoev.ru n++;
7813Sigor@sysoev.ru
7913Sigor@sysoev.ru done:
8013Sigor@sysoev.ru
8113Sigor@sysoev.ru sb->buf = b;
8213Sigor@sysoev.ru
8313Sigor@sysoev.ru return n;
8413Sigor@sysoev.ru }
8513Sigor@sysoev.ru
8613Sigor@sysoev.ru
8713Sigor@sysoev.ru nxt_uint_t
nxt_sendbuf_mem_coalesce(nxt_task_t * task,nxt_sendbuf_coalesce_t * sb)881Sigor@sysoev.ru nxt_sendbuf_mem_coalesce(nxt_task_t *task, nxt_sendbuf_coalesce_t *sb)
890Sigor@sysoev.ru {
900Sigor@sysoev.ru u_char *last;
910Sigor@sysoev.ru size_t size, total;
920Sigor@sysoev.ru nxt_buf_t *b;
930Sigor@sysoev.ru nxt_uint_t n;
940Sigor@sysoev.ru
950Sigor@sysoev.ru total = sb->size;
960Sigor@sysoev.ru last = NULL;
970Sigor@sysoev.ru n = (nxt_uint_t) -1;
980Sigor@sysoev.ru
990Sigor@sysoev.ru for (b = sb->buf; b != NULL && total < sb->limit; b = b->next) {
1000Sigor@sysoev.ru
1010Sigor@sysoev.ru nxt_prefetch(b->next);
1020Sigor@sysoev.ru
1030Sigor@sysoev.ru if (nxt_buf_is_file(b)) {
1040Sigor@sysoev.ru break;
1050Sigor@sysoev.ru }
1060Sigor@sysoev.ru
1070Sigor@sysoev.ru if (nxt_buf_is_mem(b)) {
1080Sigor@sysoev.ru
1090Sigor@sysoev.ru size = b->mem.free - b->mem.pos;
1100Sigor@sysoev.ru
1110Sigor@sysoev.ru if (size != 0) {
1120Sigor@sysoev.ru
1130Sigor@sysoev.ru if (total + size > sb->limit) {
1140Sigor@sysoev.ru size = sb->limit - total;
1150Sigor@sysoev.ru
116352Smax.romanov@nginx.com sb->limit_reached = 1;
117352Smax.romanov@nginx.com
118352Smax.romanov@nginx.com if (nxt_slow_path(size == 0)) {
1190Sigor@sysoev.ru break;
1200Sigor@sysoev.ru }
1210Sigor@sysoev.ru }
1220Sigor@sysoev.ru
1230Sigor@sysoev.ru if (b->mem.pos != last) {
1240Sigor@sysoev.ru
1250Sigor@sysoev.ru if (++n >= sb->nmax) {
126352Smax.romanov@nginx.com sb->nmax_reached = 1;
127352Smax.romanov@nginx.com
1280Sigor@sysoev.ru goto done;
1290Sigor@sysoev.ru }
1300Sigor@sysoev.ru
131521Szelenkov@nginx.com sb->iobuf[n].iov_base = b->mem.pos;
13214Sigor@sysoev.ru sb->iobuf[n].iov_len = size;
1330Sigor@sysoev.ru
1340Sigor@sysoev.ru } else {
13514Sigor@sysoev.ru sb->iobuf[n].iov_len += size;
1360Sigor@sysoev.ru }
1370Sigor@sysoev.ru
13814Sigor@sysoev.ru nxt_debug(task, "sendbuf: %ui, %p, %uz",
13914Sigor@sysoev.ru n, sb->iobuf[n].iov_base, sb->iobuf[n].iov_len);
1400Sigor@sysoev.ru
1410Sigor@sysoev.ru total += size;
1420Sigor@sysoev.ru last = b->mem.pos + size;
1430Sigor@sysoev.ru }
1440Sigor@sysoev.ru
1450Sigor@sysoev.ru } else {
1460Sigor@sysoev.ru sb->sync = 1;
1470Sigor@sysoev.ru sb->last |= nxt_buf_is_last(b);
1480Sigor@sysoev.ru }
1490Sigor@sysoev.ru }
1500Sigor@sysoev.ru
1510Sigor@sysoev.ru n++;
1520Sigor@sysoev.ru
1530Sigor@sysoev.ru done:
1540Sigor@sysoev.ru
1550Sigor@sysoev.ru sb->buf = b;
1560Sigor@sysoev.ru sb->size = total;
15742Smax.romanov@nginx.com sb->niov = n;
1580Sigor@sysoev.ru
1590Sigor@sysoev.ru return n;
1600Sigor@sysoev.ru }
1610Sigor@sysoev.ru
1620Sigor@sysoev.ru
1630Sigor@sysoev.ru size_t
nxt_sendbuf_file_coalesce(nxt_sendbuf_coalesce_t * sb)1640Sigor@sysoev.ru nxt_sendbuf_file_coalesce(nxt_sendbuf_coalesce_t *sb)
1650Sigor@sysoev.ru {
1660Sigor@sysoev.ru size_t file_start, total;
1670Sigor@sysoev.ru nxt_fd_t fd;
1680Sigor@sysoev.ru nxt_off_t size, last;
1690Sigor@sysoev.ru nxt_buf_t *b;
1700Sigor@sysoev.ru
1710Sigor@sysoev.ru b = sb->buf;
1720Sigor@sysoev.ru fd = b->file->fd;
1730Sigor@sysoev.ru
1740Sigor@sysoev.ru total = sb->size;
1750Sigor@sysoev.ru
1760Sigor@sysoev.ru for ( ;; ) {
1770Sigor@sysoev.ru
1780Sigor@sysoev.ru nxt_prefetch(b->next);
1790Sigor@sysoev.ru
1800Sigor@sysoev.ru size = b->file_end - b->file_pos;
1810Sigor@sysoev.ru
1820Sigor@sysoev.ru if (total + size >= sb->limit) {
1830Sigor@sysoev.ru total = sb->limit;
1840Sigor@sysoev.ru break;
1850Sigor@sysoev.ru }
1860Sigor@sysoev.ru
1870Sigor@sysoev.ru total += size;
1880Sigor@sysoev.ru last = b->file_pos + size;
1890Sigor@sysoev.ru
1900Sigor@sysoev.ru b = b->next;
1910Sigor@sysoev.ru
1920Sigor@sysoev.ru if (b == NULL || !nxt_buf_is_file(b)) {
1930Sigor@sysoev.ru break;
1940Sigor@sysoev.ru }
1950Sigor@sysoev.ru
1960Sigor@sysoev.ru if (b->file_pos != last || b->file->fd != fd) {
1970Sigor@sysoev.ru break;
1980Sigor@sysoev.ru }
1990Sigor@sysoev.ru }
2000Sigor@sysoev.ru
2010Sigor@sysoev.ru sb->buf = b;
2020Sigor@sysoev.ru
2030Sigor@sysoev.ru file_start = sb->size;
2040Sigor@sysoev.ru sb->size = total;
2050Sigor@sysoev.ru
2060Sigor@sysoev.ru return total - file_start;
2070Sigor@sysoev.ru }
2080Sigor@sysoev.ru
2090Sigor@sysoev.ru
2100Sigor@sysoev.ru ssize_t
nxt_sendbuf_copy_coalesce(nxt_conn_t * c,nxt_buf_mem_t * bm,nxt_buf_t * b,size_t limit)21162Sigor@sysoev.ru nxt_sendbuf_copy_coalesce(nxt_conn_t *c, nxt_buf_mem_t *bm, nxt_buf_t *b,
21262Sigor@sysoev.ru size_t limit)
2130Sigor@sysoev.ru {
2140Sigor@sysoev.ru size_t size, bsize, copied;
2150Sigor@sysoev.ru ssize_t n;
2160Sigor@sysoev.ru nxt_bool_t flush;
2170Sigor@sysoev.ru
2180Sigor@sysoev.ru size = nxt_buf_mem_used_size(&b->mem);
2190Sigor@sysoev.ru bsize = nxt_buf_mem_size(bm);
2200Sigor@sysoev.ru
2210Sigor@sysoev.ru if (bsize != 0) {
2220Sigor@sysoev.ru
2230Sigor@sysoev.ru if (size > bsize && bm->pos == bm->free) {
2240Sigor@sysoev.ru /*
2250Sigor@sysoev.ru * A data buffer size is larger than the internal
2260Sigor@sysoev.ru * buffer size and the internal buffer is empty.
2270Sigor@sysoev.ru */
2280Sigor@sysoev.ru goto no_buffer;
2290Sigor@sysoev.ru }
2300Sigor@sysoev.ru
2310Sigor@sysoev.ru if (bm->pos == NULL) {
2320Sigor@sysoev.ru bm->pos = nxt_malloc(bsize);
2330Sigor@sysoev.ru if (nxt_slow_path(bm->pos == NULL)) {
2340Sigor@sysoev.ru return NXT_ERROR;
2350Sigor@sysoev.ru }
2360Sigor@sysoev.ru
2370Sigor@sysoev.ru bm->start = bm->pos;
2380Sigor@sysoev.ru bm->free = bm->pos;
2390Sigor@sysoev.ru bm->end += (uintptr_t) bm->pos;
2400Sigor@sysoev.ru }
2410Sigor@sysoev.ru
2420Sigor@sysoev.ru copied = 0;
2430Sigor@sysoev.ru
2440Sigor@sysoev.ru flush = nxt_sendbuf_copy(bm, b, &copied);
2450Sigor@sysoev.ru
2460Sigor@sysoev.ru nxt_log_debug(c->socket.log, "sendbuf copy:%uz fl:%b", copied, flush);
2470Sigor@sysoev.ru
2480Sigor@sysoev.ru if (flush == 0) {
2490Sigor@sysoev.ru return copied;
2500Sigor@sysoev.ru }
2510Sigor@sysoev.ru
2520Sigor@sysoev.ru size = nxt_buf_mem_used_size(bm);
2530Sigor@sysoev.ru
2540Sigor@sysoev.ru if (size == 0 && nxt_buf_is_sync(b)) {
2550Sigor@sysoev.ru goto done;
2560Sigor@sysoev.ru }
2570Sigor@sysoev.ru
2580Sigor@sysoev.ru n = c->io->send(c, bm->pos, nxt_min(size, limit));
2590Sigor@sysoev.ru
2600Sigor@sysoev.ru nxt_log_debug(c->socket.log, "sendbuf sent:%z", n);
2610Sigor@sysoev.ru
2620Sigor@sysoev.ru if (n > 0) {
2630Sigor@sysoev.ru bm->pos += n;
2640Sigor@sysoev.ru
2650Sigor@sysoev.ru if (bm->pos == bm->free) {
2660Sigor@sysoev.ru bm->pos = bm->start;
2670Sigor@sysoev.ru bm->free = bm->start;
2680Sigor@sysoev.ru }
2690Sigor@sysoev.ru
2700Sigor@sysoev.ru n = 0;
2710Sigor@sysoev.ru }
2720Sigor@sysoev.ru
2730Sigor@sysoev.ru return (copied != 0) ? (ssize_t) copied : n;
2740Sigor@sysoev.ru }
2750Sigor@sysoev.ru
2760Sigor@sysoev.ru /* No internal buffering. */
2770Sigor@sysoev.ru
2780Sigor@sysoev.ru if (size == 0 && nxt_buf_is_sync(b)) {
2790Sigor@sysoev.ru goto done;
2800Sigor@sysoev.ru }
2810Sigor@sysoev.ru
2820Sigor@sysoev.ru no_buffer:
2830Sigor@sysoev.ru
2840Sigor@sysoev.ru return c->io->send(c, b->mem.pos, nxt_min(size, limit));
2850Sigor@sysoev.ru
2860Sigor@sysoev.ru done:
2870Sigor@sysoev.ru
2880Sigor@sysoev.ru nxt_log_debug(c->socket.log, "sendbuf done");
2890Sigor@sysoev.ru
2900Sigor@sysoev.ru return 0;
2910Sigor@sysoev.ru }
2920Sigor@sysoev.ru
2930Sigor@sysoev.ru
2940Sigor@sysoev.ru static nxt_bool_t
nxt_sendbuf_copy(nxt_buf_mem_t * bm,nxt_buf_t * b,size_t * copied)2950Sigor@sysoev.ru nxt_sendbuf_copy(nxt_buf_mem_t *bm, nxt_buf_t *b, size_t *copied)
2960Sigor@sysoev.ru {
2970Sigor@sysoev.ru size_t size, bsize;
2980Sigor@sysoev.ru nxt_bool_t flush;
2990Sigor@sysoev.ru
3000Sigor@sysoev.ru flush = 0;
3010Sigor@sysoev.ru
3020Sigor@sysoev.ru do {
3030Sigor@sysoev.ru nxt_prefetch(b->next);
3040Sigor@sysoev.ru
3050Sigor@sysoev.ru if (nxt_buf_is_mem(b)) {
3060Sigor@sysoev.ru bsize = bm->end - bm->free;
3070Sigor@sysoev.ru size = b->mem.free - b->mem.pos;
3080Sigor@sysoev.ru size = nxt_min(size, bsize);
3090Sigor@sysoev.ru
3100Sigor@sysoev.ru nxt_memcpy(bm->free, b->mem.pos, size);
3110Sigor@sysoev.ru
3120Sigor@sysoev.ru *copied += size;
3130Sigor@sysoev.ru bm->free += size;
3140Sigor@sysoev.ru
3150Sigor@sysoev.ru if (bm->free == bm->end) {
3160Sigor@sysoev.ru return 1;
3170Sigor@sysoev.ru }
3180Sigor@sysoev.ru }
3190Sigor@sysoev.ru
3200Sigor@sysoev.ru flush |= nxt_buf_is_flush(b) || nxt_buf_is_last(b);
3210Sigor@sysoev.ru
3220Sigor@sysoev.ru b = b->next;
3230Sigor@sysoev.ru
3240Sigor@sysoev.ru } while (b != NULL);
3250Sigor@sysoev.ru
3260Sigor@sysoev.ru return flush;
3270Sigor@sysoev.ru }
3280Sigor@sysoev.ru
3290Sigor@sysoev.ru
3300Sigor@sysoev.ru nxt_buf_t *
nxt_sendbuf_update(nxt_buf_t * b,size_t sent)3310Sigor@sysoev.ru nxt_sendbuf_update(nxt_buf_t *b, size_t sent)
3320Sigor@sysoev.ru {
3330Sigor@sysoev.ru size_t size;
3340Sigor@sysoev.ru
3350Sigor@sysoev.ru while (b != NULL) {
3360Sigor@sysoev.ru
3370Sigor@sysoev.ru nxt_prefetch(b->next);
3380Sigor@sysoev.ru
3390Sigor@sysoev.ru if (!nxt_buf_is_sync(b)) {
3400Sigor@sysoev.ru
3410Sigor@sysoev.ru size = nxt_buf_used_size(b);
3420Sigor@sysoev.ru
3430Sigor@sysoev.ru if (size != 0) {
3440Sigor@sysoev.ru
3450Sigor@sysoev.ru if (sent == 0) {
3460Sigor@sysoev.ru break;
3470Sigor@sysoev.ru }
3480Sigor@sysoev.ru
3490Sigor@sysoev.ru if (sent < size) {
3500Sigor@sysoev.ru
3510Sigor@sysoev.ru if (nxt_buf_is_mem(b)) {
3520Sigor@sysoev.ru b->mem.pos += sent;
3530Sigor@sysoev.ru }
3540Sigor@sysoev.ru
3550Sigor@sysoev.ru if (nxt_buf_is_file(b)) {
3560Sigor@sysoev.ru b->file_pos += sent;
3570Sigor@sysoev.ru }
3580Sigor@sysoev.ru
3590Sigor@sysoev.ru break;
3600Sigor@sysoev.ru }
3610Sigor@sysoev.ru
3620Sigor@sysoev.ru /* b->mem.free is NULL in file-only buffer. */
3630Sigor@sysoev.ru b->mem.pos = b->mem.free;
3640Sigor@sysoev.ru
3650Sigor@sysoev.ru if (nxt_buf_is_file(b)) {
3660Sigor@sysoev.ru b->file_pos = b->file_end;
3670Sigor@sysoev.ru }
3680Sigor@sysoev.ru
3690Sigor@sysoev.ru sent -= size;
3700Sigor@sysoev.ru }
3710Sigor@sysoev.ru }
3720Sigor@sysoev.ru
3730Sigor@sysoev.ru b = b->next;
3740Sigor@sysoev.ru }
3750Sigor@sysoev.ru
3760Sigor@sysoev.ru return b;
3770Sigor@sysoev.ru }
3780Sigor@sysoev.ru
3790Sigor@sysoev.ru
3800Sigor@sysoev.ru nxt_buf_t *
nxt_sendbuf_completion(nxt_task_t * task,nxt_work_queue_t * wq,nxt_buf_t * b)381592Sigor@sysoev.ru nxt_sendbuf_completion(nxt_task_t *task, nxt_work_queue_t *wq, nxt_buf_t *b)
382431Sigor@sysoev.ru {
383431Sigor@sysoev.ru while (b != NULL) {
384431Sigor@sysoev.ru
385608Sigor@sysoev.ru if (!nxt_buf_is_sync(b) && nxt_buf_used_size(b) != 0) {
386431Sigor@sysoev.ru break;
387431Sigor@sysoev.ru }
388431Sigor@sysoev.ru
389*1269Sigor@sysoev.ru b = nxt_sendbuf_coalesce_completion(task, wq, b);
390431Sigor@sysoev.ru }
391431Sigor@sysoev.ru
392431Sigor@sysoev.ru return b;
393431Sigor@sysoev.ru }
394608Sigor@sysoev.ru
395608Sigor@sysoev.ru
396608Sigor@sysoev.ru void
nxt_sendbuf_drain(nxt_task_t * task,nxt_work_queue_t * wq,nxt_buf_t * b)397608Sigor@sysoev.ru nxt_sendbuf_drain(nxt_task_t *task, nxt_work_queue_t *wq, nxt_buf_t *b)
398608Sigor@sysoev.ru {
399608Sigor@sysoev.ru while (b != NULL) {
400*1269Sigor@sysoev.ru b = nxt_sendbuf_coalesce_completion(task, wq, b);
401608Sigor@sysoev.ru }
402608Sigor@sysoev.ru }
403*1269Sigor@sysoev.ru
404*1269Sigor@sysoev.ru
405*1269Sigor@sysoev.ru static nxt_buf_t *
nxt_sendbuf_coalesce_completion(nxt_task_t * task,nxt_work_queue_t * wq,nxt_buf_t * start)406*1269Sigor@sysoev.ru nxt_sendbuf_coalesce_completion(nxt_task_t *task, nxt_work_queue_t *wq,
407*1269Sigor@sysoev.ru nxt_buf_t *start)
408*1269Sigor@sysoev.ru {
409*1269Sigor@sysoev.ru nxt_buf_t *b, *next, **last, *rest, **last_rest;
410*1269Sigor@sysoev.ru nxt_work_handler_t handler;
411*1269Sigor@sysoev.ru
412*1269Sigor@sysoev.ru rest = NULL;
413*1269Sigor@sysoev.ru last_rest = &rest;
414*1269Sigor@sysoev.ru last = &start->next;
415*1269Sigor@sysoev.ru b = start;
416*1269Sigor@sysoev.ru handler = b->completion_handler;
417*1269Sigor@sysoev.ru
418*1269Sigor@sysoev.ru for ( ;; ) {
419*1269Sigor@sysoev.ru next = b->next;
420*1269Sigor@sysoev.ru if (next == NULL) {
421*1269Sigor@sysoev.ru break;
422*1269Sigor@sysoev.ru }
423*1269Sigor@sysoev.ru
424*1269Sigor@sysoev.ru b->next = NULL;
425*1269Sigor@sysoev.ru b = next;
426*1269Sigor@sysoev.ru
427*1269Sigor@sysoev.ru if (!nxt_buf_is_sync(b) && nxt_buf_used_size(b) != 0) {
428*1269Sigor@sysoev.ru *last_rest = b;
429*1269Sigor@sysoev.ru break;
430*1269Sigor@sysoev.ru }
431*1269Sigor@sysoev.ru
432*1269Sigor@sysoev.ru if (handler == b->completion_handler) {
433*1269Sigor@sysoev.ru *last = b;
434*1269Sigor@sysoev.ru last = &b->next;
435*1269Sigor@sysoev.ru
436*1269Sigor@sysoev.ru } else {
437*1269Sigor@sysoev.ru *last_rest = b;
438*1269Sigor@sysoev.ru last_rest = &b->next;
439*1269Sigor@sysoev.ru }
440*1269Sigor@sysoev.ru }
441*1269Sigor@sysoev.ru
442*1269Sigor@sysoev.ru nxt_work_queue_add(wq, handler, task, start, start->parent);
443*1269Sigor@sysoev.ru
444*1269Sigor@sysoev.ru return rest;
445*1269Sigor@sysoev.ru }
446