Igor Sysoev | 0e499db | 2003-11-27 07:45:22 +0000 | [diff] [blame] | 1 | |
Igor Sysoev | d94049b | 2004-02-29 21:03:02 +0000 | [diff] [blame] | 2 | /* |
| 3 | * Copyright (C) 2002-2004 Igor Sysoev, http://sysoev.ru/en/ |
| 4 | */ |
| 5 | |
| 6 | |
Igor Sysoev | 0e499db | 2003-11-27 07:45:22 +0000 | [diff] [blame] | 7 | #include <ngx_config.h> |
| 8 | #include <ngx_core.h> |
| 9 | #include <ngx_event.h> |
| 10 | |
| 11 | |
| 12 | ngx_chain_t *ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in) |
| 13 | { |
| 14 | int fd; |
Igor Sysoev | 10a543a | 2004-03-16 07:10:12 +0000 | [diff] [blame] | 15 | u_char *prev; |
Igor Sysoev | 0e499db | 2003-11-27 07:45:22 +0000 | [diff] [blame] | 16 | off_t fprev; |
Igor Sysoev | 764543e | 2003-11-27 19:01:37 +0000 | [diff] [blame] | 17 | size_t sent, size; |
Igor Sysoev | 0e499db | 2003-11-27 07:45:22 +0000 | [diff] [blame] | 18 | ssize_t n; |
| 19 | ngx_int_t eintr; |
Igor Sysoev | 764543e | 2003-11-27 19:01:37 +0000 | [diff] [blame] | 20 | ngx_err_t err; |
Igor Sysoev | 0e499db | 2003-11-27 07:45:22 +0000 | [diff] [blame] | 21 | sendfilevec_t *sfv; |
| 22 | ngx_array_t vec; |
| 23 | ngx_event_t *wev; |
Igor Sysoev | 8ae18a1 | 2004-02-18 15:45:21 +0000 | [diff] [blame] | 24 | ngx_chain_t *cl, *tail; |
Igor Sysoev | 0e499db | 2003-11-27 07:45:22 +0000 | [diff] [blame] | 25 | |
| 26 | wev = c->write; |
| 27 | |
| 28 | if (!wev->ready) { |
| 29 | return in; |
| 30 | } |
| 31 | |
| 32 | do { |
| 33 | fd = SFV_FD_SELF; |
| 34 | prev = NULL; |
Igor Sysoev | 764543e | 2003-11-27 19:01:37 +0000 | [diff] [blame] | 35 | fprev = 0; |
Igor Sysoev | 0e499db | 2003-11-27 07:45:22 +0000 | [diff] [blame] | 36 | sfv = NULL; |
| 37 | eintr = 0; |
| 38 | sent = 0; |
| 39 | |
Igor Sysoev | 764543e | 2003-11-27 19:01:37 +0000 | [diff] [blame] | 40 | ngx_init_array(vec, c->pool, 10, sizeof(sendfilevec_t), |
| 41 | NGX_CHAIN_ERROR); |
| 42 | |
Igor Sysoev | 0e499db | 2003-11-27 07:45:22 +0000 | [diff] [blame] | 43 | /* create the sendfilevec and coalesce the neighbouring hunks */ |
| 44 | |
Igor Sysoev | 8ae18a1 | 2004-02-18 15:45:21 +0000 | [diff] [blame] | 45 | for (cl = in; cl && vec.nelts < IOV_MAX; cl = cl->next) { |
Igor Sysoev | 0e499db | 2003-11-27 07:45:22 +0000 | [diff] [blame] | 46 | if (ngx_hunk_special(cl->hunk)) { |
| 47 | continue; |
| 48 | } |
| 49 | |
| 50 | if (ngx_hunk_in_memory_only(cl->hunk)) { |
| 51 | fd = SFV_FD_SELF; |
| 52 | |
| 53 | if (prev == cl->hunk->pos) { |
| 54 | sfv->sfv_len += cl->hunk->last - cl->hunk->pos; |
| 55 | |
| 56 | } else { |
| 57 | ngx_test_null(sfv, ngx_push_array(&vec), NGX_CHAIN_ERROR); |
| 58 | sfv->sfv_fd = SFV_FD_SELF; |
| 59 | sfv->sfv_flag = 0; |
Igor Sysoev | 764543e | 2003-11-27 19:01:37 +0000 | [diff] [blame] | 60 | sfv->sfv_off = (off_t) (uintptr_t) cl->hunk->pos; |
Igor Sysoev | 0e499db | 2003-11-27 07:45:22 +0000 | [diff] [blame] | 61 | sfv->sfv_len = cl->hunk->last - cl->hunk->pos; |
| 62 | } |
| 63 | |
| 64 | prev = cl->hunk->last; |
| 65 | |
| 66 | } else { |
| 67 | prev = NULL; |
| 68 | |
| 69 | if (fd == cl->hunk->file->fd && fprev == cl->hunk->file_pos) { |
| 70 | sfv->sfv_len += cl->hunk->file_last - cl->hunk->file_pos; |
| 71 | |
| 72 | } else { |
| 73 | ngx_test_null(sfv, ngx_push_array(&vec), NGX_CHAIN_ERROR); |
| 74 | fd = cl->hunk->file->fd; |
| 75 | sfv->sfv_fd = fd; |
| 76 | sfv->sfv_flag = 0; |
| 77 | sfv->sfv_off = cl->hunk->file_pos; |
| 78 | sfv->sfv_len = cl->hunk->file_last - cl->hunk->file_pos; |
| 79 | } |
| 80 | |
| 81 | fprev = cl->hunk->file_last; |
| 82 | } |
| 83 | } |
| 84 | |
Igor Sysoev | 8ae18a1 | 2004-02-18 15:45:21 +0000 | [diff] [blame] | 85 | /* |
| 86 | * the tail is the rest of the chain that exceeded a single |
| 87 | * sendfilev() capability, IOV_MAX in Solaris is only 16 |
| 88 | */ |
| 89 | |
| 90 | tail = cl; |
| 91 | |
Igor Sysoev | 764543e | 2003-11-27 19:01:37 +0000 | [diff] [blame] | 92 | n = sendfilev(c->fd, vec.elts, vec.nelts, &sent); |
Igor Sysoev | 0e499db | 2003-11-27 07:45:22 +0000 | [diff] [blame] | 93 | |
| 94 | if (n == -1) { |
| 95 | err = ngx_errno; |
| 96 | |
Igor Sysoev | 0e499db | 2003-11-27 07:45:22 +0000 | [diff] [blame] | 97 | if (err == NGX_EAGAIN || err == NGX_EINTR) { |
Igor Sysoev | 54498db | 2004-02-11 17:08:49 +0000 | [diff] [blame] | 98 | if (err == NGX_EINTR) { |
| 99 | eintr = 1; |
| 100 | } |
| 101 | |
| 102 | ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, err, |
Igor Sysoev | 0e499db | 2003-11-27 07:45:22 +0000 | [diff] [blame] | 103 | "sendfilev() sent only " SIZE_T_FMT " bytes", |
| 104 | sent); |
Igor Sysoev | 54498db | 2004-02-11 17:08:49 +0000 | [diff] [blame] | 105 | |
Igor Sysoev | 0e499db | 2003-11-27 07:45:22 +0000 | [diff] [blame] | 106 | } else { |
| 107 | wev->error = 1; |
Igor Sysoev | 54498db | 2004-02-11 17:08:49 +0000 | [diff] [blame] | 108 | ngx_connection_error(c, err, "sendfilev() failed"); |
Igor Sysoev | 0e499db | 2003-11-27 07:45:22 +0000 | [diff] [blame] | 109 | return NGX_CHAIN_ERROR; |
| 110 | } |
| 111 | } |
| 112 | |
Igor Sysoev | 54498db | 2004-02-11 17:08:49 +0000 | [diff] [blame] | 113 | ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, |
| 114 | "sendfilev: %d " SIZE_T_FMT, n, sent); |
Igor Sysoev | 0e499db | 2003-11-27 07:45:22 +0000 | [diff] [blame] | 115 | |
| 116 | c->sent += sent; |
| 117 | |
| 118 | for (cl = in; cl; cl = cl->next) { |
| 119 | |
| 120 | if (ngx_hunk_special(cl->hunk)) { |
| 121 | continue; |
| 122 | } |
| 123 | |
| 124 | if (sent == 0) { |
| 125 | break; |
| 126 | } |
| 127 | |
| 128 | size = ngx_hunk_size(cl->hunk); |
| 129 | |
| 130 | if (sent >= size) { |
| 131 | sent -= size; |
| 132 | |
| 133 | if (cl->hunk->type & NGX_HUNK_IN_MEMORY) { |
| 134 | cl->hunk->pos = cl->hunk->last; |
| 135 | } |
| 136 | |
| 137 | if (cl->hunk->type & NGX_HUNK_FILE) { |
| 138 | cl->hunk->file_pos = cl->hunk->file_last; |
| 139 | } |
| 140 | |
| 141 | continue; |
| 142 | } |
| 143 | |
| 144 | if (cl->hunk->type & NGX_HUNK_IN_MEMORY) { |
| 145 | cl->hunk->pos += sent; |
| 146 | } |
| 147 | |
| 148 | if (cl->hunk->type & NGX_HUNK_FILE) { |
| 149 | cl->hunk->file_pos += sent; |
| 150 | } |
| 151 | |
| 152 | break; |
| 153 | } |
| 154 | |
| 155 | in = cl; |
| 156 | |
Igor Sysoev | 8ae18a1 | 2004-02-18 15:45:21 +0000 | [diff] [blame] | 157 | /* "tail == in" means that a single sendfilev() is complete */ |
| 158 | |
| 159 | } while ((tail && tail == in) || eintr); |
Igor Sysoev | 0e499db | 2003-11-27 07:45:22 +0000 | [diff] [blame] | 160 | |
| 161 | if (in) { |
| 162 | wev->ready = 0; |
| 163 | } |
| 164 | |
| 165 | return in; |
| 166 | } |