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