src/os/unix/ngx_readv_chain.c - nginx-1.7.10

Functions defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_event.h>


  8. ssize_t
  9. ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain, off_t limit)
  10. {
  11.     u_char        *prev;
  12.     ssize_t        n, size;
  13.     ngx_err_t      err;
  14.     ngx_array_t    vec;
  15.     ngx_event_t   *rev;
  16.     struct iovec  *iov, iovs[NGX_IOVS_PREALLOCATE];

  17.     rev = c->read;

  18. #if (NGX_HAVE_KQUEUE)

  19.     if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
  20.         ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
  21.                        "readv: eof:%d, avail:%d, err:%d",
  22.                        rev->pending_eof, rev->available, rev->kq_errno);

  23.         if (rev->available == 0) {
  24.             if (rev->pending_eof) {
  25.                 rev->ready = 0;
  26.                 rev->eof = 1;

  27.                 ngx_log_error(NGX_LOG_INFO, c->log, rev->kq_errno,
  28.                               "kevent() reported about an closed connection");

  29.                 if (rev->kq_errno) {
  30.                     rev->error = 1;
  31.                     ngx_set_socket_errno(rev->kq_errno);
  32.                     return NGX_ERROR;
  33.                 }

  34.                 return 0;

  35.             } else {
  36.                 return NGX_AGAIN;
  37.             }
  38.         }
  39.     }

  40. #endif

  41.     prev = NULL;
  42.     iov = NULL;
  43.     size = 0;

  44.     vec.elts = iovs;
  45.     vec.nelts = 0;
  46.     vec.size = sizeof(struct iovec);
  47.     vec.nalloc = NGX_IOVS_PREALLOCATE;
  48.     vec.pool = c->pool;

  49.     /* coalesce the neighbouring bufs */

  50.     while (chain) {
  51.         n = chain->buf->end - chain->buf->last;

  52.         if (limit) {
  53.             if (size >= limit) {
  54.                 break;
  55.             }

  56.             if (size + n > limit) {
  57.                 n = (ssize_t) (limit - size);
  58.             }
  59.         }

  60.         if (prev == chain->buf->last) {
  61.             iov->iov_len += n;

  62.         } else {
  63.             if (vec.nelts >= IOV_MAX) {
  64.                 break;
  65.             }

  66.             iov = ngx_array_push(&vec);
  67.             if (iov == NULL) {
  68.                 return NGX_ERROR;
  69.             }

  70.             iov->iov_base = (void *) chain->buf->last;
  71.             iov->iov_len = n;
  72.         }

  73.         size += n;
  74.         prev = chain->buf->end;
  75.         chain = chain->next;
  76.     }

  77.     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
  78.                    "readv: %d, last:%d", vec.nelts, iov->iov_len);

  79.     do {
  80.         n = readv(c->fd, (struct iovec *) vec.elts, vec.nelts);

  81.         if (n >= 0) {

  82. #if (NGX_HAVE_KQUEUE)

  83.             if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
  84.                 rev->available -= n;

  85.                 /*
  86.                  * rev->available may be negative here because some additional
  87.                  * bytes may be received between kevent() and recv()
  88.                  */

  89.                 if (rev->available <= 0) {
  90.                     if (!rev->pending_eof) {
  91.                         rev->ready = 0;
  92.                     }

  93.                     if (rev->available < 0) {
  94.                         rev->available = 0;
  95.                     }
  96.                 }

  97.                 if (n == 0) {

  98.                     /*
  99.                      * on FreeBSD recv() may return 0 on closed socket
  100.                      * even if kqueue reported about available data
  101.                      */

  102. #if 0
  103.                     ngx_log_error(NGX_LOG_ALERT, c->log, 0,
  104.                                   "readv() returned 0 while kevent() reported "
  105.                                   "%d available bytes", rev->available);
  106. #endif

  107.                     rev->ready = 0;
  108.                     rev->eof = 1;
  109.                     rev->available = 0;
  110.                 }

  111.                 return n;
  112.             }

  113. #endif /* NGX_HAVE_KQUEUE */

  114.             if (n < size && !(ngx_event_flags & NGX_USE_GREEDY_EVENT)) {
  115.                 rev->ready = 0;
  116.             }

  117.             if (n == 0) {
  118.                 rev->eof = 1;
  119.             }

  120.             return n;
  121.         }

  122.         err = ngx_socket_errno;

  123.         if (err == NGX_EAGAIN || err == NGX_EINTR) {
  124.             ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
  125.                            "readv() not ready");
  126.             n = NGX_AGAIN;

  127.         } else {
  128.             n = ngx_connection_error(c, err, "readv() failed");
  129.             break;
  130.         }

  131.     } while (err == NGX_EINTR);

  132.     rev->ready = 0;

  133.     if (n == NGX_ERROR) {
  134.         c->read->error = 1;
  135.     }

  136.     return n;
  137. }