src/os/unix/ngx_solaris_sendfilev_chain.c - nginx source code

Data types defined

Functions defined

Macros 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. #if (NGX_TEST_BUILD_SOLARIS_SENDFILEV)

  9. /* Solaris declarations */

  10. typedef struct sendfilevec {
  11.     int     sfv_fd;
  12.     u_int   sfv_flag;
  13.     off_t   sfv_off;
  14.     size_t  sfv_len;
  15. } sendfilevec_t;

  16. #define SFV_FD_SELF  -2

  17. static ssize_t sendfilev(int fd, const struct sendfilevec *vec,
  18.     int sfvcnt, size_t *xferred)
  19. {
  20.     return -1;
  21. }

  22. ngx_chain_t *ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in,
  23.     off_t limit);

  24. #endif


  25. #define NGX_SENDFILEVECS  NGX_IOVS_PREALLOCATE


  26. ngx_chain_t *
  27. ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
  28. {
  29.     int             fd;
  30.     u_char         *prev;
  31.     off_t           size, send, prev_send, aligned, fprev;
  32.     size_t          sent;
  33.     ssize_t         n;
  34.     ngx_int_t       eintr;
  35.     ngx_err_t       err;
  36.     ngx_buf_t      *file;
  37.     ngx_uint_t      nsfv;
  38.     sendfilevec_t  *sfv, sfvs[NGX_SENDFILEVECS];
  39.     ngx_event_t    *wev;
  40.     ngx_chain_t    *cl;

  41.     wev = c->write;

  42.     if (!wev->ready) {
  43.         return in;
  44.     }

  45.     if (!c->sendfile) {
  46.         return ngx_writev_chain(c, in, limit);
  47.     }


  48.     /* the maximum limit size is the maximum size_t value - the page size */

  49.     if (limit == 0 || limit > (off_t) (NGX_MAX_SIZE_T_VALUE - ngx_pagesize)) {
  50.         limit = NGX_MAX_SIZE_T_VALUE - ngx_pagesize;
  51.     }


  52.     send = 0;

  53.     for ( ;; ) {
  54.         fd = SFV_FD_SELF;
  55.         prev = NULL;
  56.         fprev = 0;
  57.         file = NULL;
  58.         sfv = NULL;
  59.         eintr = 0;
  60.         sent = 0;
  61.         prev_send = send;

  62.         nsfv = 0;

  63.         /* create the sendfilevec and coalesce the neighbouring bufs */

  64.         for (cl = in; cl && send < limit; cl = cl->next) {

  65.             if (ngx_buf_special(cl->buf)) {
  66.                 continue;
  67.             }

  68.             if (ngx_buf_in_memory_only(cl->buf)) {
  69.                 fd = SFV_FD_SELF;

  70.                 size = cl->buf->last - cl->buf->pos;

  71.                 if (send + size > limit) {
  72.                     size = limit - send;
  73.                 }

  74.                 if (prev == cl->buf->pos) {
  75.                     sfv->sfv_len += (size_t) size;

  76.                 } else {
  77.                     if (nsfv == NGX_SENDFILEVECS) {
  78.                         break;
  79.                     }

  80.                     sfv = &sfvs[nsfv++];

  81.                     sfv->sfv_fd = SFV_FD_SELF;
  82.                     sfv->sfv_flag = 0;
  83.                     sfv->sfv_off = (off_t) (uintptr_t) cl->buf->pos;
  84.                     sfv->sfv_len = (size_t) size;
  85.                 }

  86.                 prev = cl->buf->pos + (size_t) size;
  87.                 send += size;

  88.             } else {
  89.                 prev = NULL;

  90.                 size = cl->buf->file_last - cl->buf->file_pos;

  91.                 if (send + size > limit) {
  92.                     size = limit - send;

  93.                     aligned = (cl->buf->file_pos + size + ngx_pagesize - 1)
  94.                                & ~((off_t) ngx_pagesize - 1);

  95.                     if (aligned <= cl->buf->file_last) {
  96.                         size = aligned - cl->buf->file_pos;
  97.                     }
  98.                 }

  99.                 if (fd == cl->buf->file->fd && fprev == cl->buf->file_pos) {
  100.                     sfv->sfv_len += (size_t) size;

  101.                 } else {
  102.                     if (nsfv == NGX_SENDFILEVECS) {
  103.                         break;
  104.                     }

  105.                     sfv = &sfvs[nsfv++];

  106.                     fd = cl->buf->file->fd;
  107.                     sfv->sfv_fd = fd;
  108.                     sfv->sfv_flag = 0;
  109.                     sfv->sfv_off = cl->buf->file_pos;
  110.                     sfv->sfv_len = (size_t) size;
  111.                 }

  112.                 file = cl->buf;
  113.                 fprev = cl->buf->file_pos + size;
  114.                 send += size;
  115.             }
  116.         }

  117.         n = sendfilev(c->fd, sfvs, nsfv, &sent);

  118.         if (n == -1) {
  119.             err = ngx_errno;

  120.             switch (err) {
  121.             case NGX_EAGAIN:
  122.                 break;

  123.             case NGX_EINTR:
  124.                 eintr = 1;
  125.                 break;

  126.             default:
  127.                 wev->error = 1;
  128.                 ngx_connection_error(c, err, "sendfilev() failed");
  129.                 return NGX_CHAIN_ERROR;
  130.             }

  131.             ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, err,
  132.                           "sendfilev() sent only %uz bytes", sent);

  133.         } else if (n == 0 && sent == 0) {

  134.             /*
  135.              * sendfilev() is documented to return -1 with errno
  136.              * set to EINVAL if svf_len is greater than the file size,
  137.              * but at least Solaris 11 returns 0 instead
  138.              */

  139.             if (file) {
  140.                 ngx_log_error(NGX_LOG_ALERT, c->log, 0,
  141.                         "sendfilev() reported that \"%s\" was truncated at %O",
  142.                         file->file->name.data, file->file_pos);

  143.             } else {
  144.                 ngx_log_error(NGX_LOG_ALERT, c->log, 0,
  145.                               "sendfilev() returned 0 with memory buffers");
  146.             }

  147.             return NGX_CHAIN_ERROR;
  148.         }

  149.         ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
  150.                        "sendfilev: %z %z", n, sent);

  151.         c->sent += sent;

  152.         in = ngx_chain_update_sent(in, sent);

  153.         if (eintr) {
  154.             send = prev_send + sent;
  155.             continue;
  156.         }

  157.         if (send - prev_send != (off_t) sent) {
  158.             wev->ready = 0;
  159.             return in;
  160.         }

  161.         if (send >= limit || in == NULL) {
  162.             return in;
  163.         }
  164.     }
  165. }