1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/ipc/chromium/src/third_party/libevent/buffer_iocp.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,325 @@ 1.4 +/* 1.5 + * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson 1.6 + * 1.7 + * Redistribution and use in source and binary forms, with or without 1.8 + * modification, are permitted provided that the following conditions 1.9 + * are met: 1.10 + * 1. Redistributions of source code must retain the above copyright 1.11 + * notice, this list of conditions and the following disclaimer. 1.12 + * 2. Redistributions in binary form must reproduce the above copyright 1.13 + * notice, this list of conditions and the following disclaimer in the 1.14 + * documentation and/or other materials provided with the distribution. 1.15 + * 3. The name of the author may not be used to endorse or promote products 1.16 + * derived from this software without specific prior written permission. 1.17 + * 1.18 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1.19 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1.20 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1.21 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1.22 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1.23 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.24 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.25 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.26 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 1.27 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.28 + */ 1.29 + 1.30 +/** 1.31 + @file buffer_iocp.c 1.32 + 1.33 + This module implements overlapped read and write functions for evbuffer 1.34 + objects on Windows. 1.35 +*/ 1.36 + 1.37 +#include "event2/buffer.h" 1.38 +#include "event2/buffer_compat.h" 1.39 +#include "event2/util.h" 1.40 +#include "event2/thread.h" 1.41 +#include "event2/event-config.h" 1.42 +#include "util-internal.h" 1.43 +#include "evthread-internal.h" 1.44 +#include "evbuffer-internal.h" 1.45 +#include "iocp-internal.h" 1.46 +#include "mm-internal.h" 1.47 + 1.48 +#include <winsock2.h> 1.49 +#include <windows.h> 1.50 +#include <stdio.h> 1.51 + 1.52 +#define MAX_WSABUFS 16 1.53 + 1.54 +/** An evbuffer that can handle overlapped IO. */ 1.55 +struct evbuffer_overlapped { 1.56 + struct evbuffer buffer; 1.57 + /** The socket that we're doing overlapped IO on. */ 1.58 + evutil_socket_t fd; 1.59 + 1.60 + /** pending I/O type */ 1.61 + unsigned read_in_progress : 1; 1.62 + unsigned write_in_progress : 1; 1.63 + 1.64 + /** The first pinned chain in the buffer. */ 1.65 + struct evbuffer_chain *first_pinned; 1.66 + 1.67 + /** How many chains are pinned; how many of the fields in buffers 1.68 + * are we using. */ 1.69 + int n_buffers; 1.70 + WSABUF buffers[MAX_WSABUFS]; 1.71 +}; 1.72 + 1.73 +/** Given an evbuffer, return the correponding evbuffer structure, or NULL if 1.74 + * the evbuffer isn't overlapped. */ 1.75 +static inline struct evbuffer_overlapped * 1.76 +upcast_evbuffer(struct evbuffer *buf) 1.77 +{ 1.78 + if (!buf || !buf->is_overlapped) 1.79 + return NULL; 1.80 + return EVUTIL_UPCAST(buf, struct evbuffer_overlapped, buffer); 1.81 +} 1.82 + 1.83 +/** Unpin all the chains noted as pinned in 'eo'. */ 1.84 +static void 1.85 +pin_release(struct evbuffer_overlapped *eo, unsigned flag) 1.86 +{ 1.87 + int i; 1.88 + struct evbuffer_chain *next, *chain = eo->first_pinned; 1.89 + 1.90 + for (i = 0; i < eo->n_buffers; ++i) { 1.91 + EVUTIL_ASSERT(chain); 1.92 + next = chain->next; 1.93 + _evbuffer_chain_unpin(chain, flag); 1.94 + chain = next; 1.95 + } 1.96 +} 1.97 + 1.98 +void 1.99 +evbuffer_commit_read(struct evbuffer *evbuf, ev_ssize_t nBytes) 1.100 +{ 1.101 + struct evbuffer_overlapped *buf = upcast_evbuffer(evbuf); 1.102 + struct evbuffer_chain **chainp; 1.103 + size_t remaining, len; 1.104 + unsigned i; 1.105 + 1.106 + EVBUFFER_LOCK(evbuf); 1.107 + EVUTIL_ASSERT(buf->read_in_progress && !buf->write_in_progress); 1.108 + EVUTIL_ASSERT(nBytes >= 0); /* XXXX Can this be false? */ 1.109 + 1.110 + evbuffer_unfreeze(evbuf, 0); 1.111 + 1.112 + chainp = evbuf->last_with_datap; 1.113 + if (!((*chainp)->flags & EVBUFFER_MEM_PINNED_R)) 1.114 + chainp = &(*chainp)->next; 1.115 + remaining = nBytes; 1.116 + for (i = 0; remaining > 0 && i < (unsigned)buf->n_buffers; ++i) { 1.117 + EVUTIL_ASSERT(*chainp); 1.118 + len = buf->buffers[i].len; 1.119 + if (remaining < len) 1.120 + len = remaining; 1.121 + (*chainp)->off += len; 1.122 + evbuf->last_with_datap = chainp; 1.123 + remaining -= len; 1.124 + chainp = &(*chainp)->next; 1.125 + } 1.126 + 1.127 + pin_release(buf, EVBUFFER_MEM_PINNED_R); 1.128 + 1.129 + buf->read_in_progress = 0; 1.130 + 1.131 + evbuf->total_len += nBytes; 1.132 + evbuf->n_add_for_cb += nBytes; 1.133 + 1.134 + evbuffer_invoke_callbacks(evbuf); 1.135 + 1.136 + _evbuffer_decref_and_unlock(evbuf); 1.137 +} 1.138 + 1.139 +void 1.140 +evbuffer_commit_write(struct evbuffer *evbuf, ev_ssize_t nBytes) 1.141 +{ 1.142 + struct evbuffer_overlapped *buf = upcast_evbuffer(evbuf); 1.143 + 1.144 + EVBUFFER_LOCK(evbuf); 1.145 + EVUTIL_ASSERT(buf->write_in_progress && !buf->read_in_progress); 1.146 + evbuffer_unfreeze(evbuf, 1); 1.147 + evbuffer_drain(evbuf, nBytes); 1.148 + pin_release(buf,EVBUFFER_MEM_PINNED_W); 1.149 + buf->write_in_progress = 0; 1.150 + _evbuffer_decref_and_unlock(evbuf); 1.151 +} 1.152 + 1.153 +struct evbuffer * 1.154 +evbuffer_overlapped_new(evutil_socket_t fd) 1.155 +{ 1.156 + struct evbuffer_overlapped *evo; 1.157 + 1.158 + evo = mm_calloc(1, sizeof(struct evbuffer_overlapped)); 1.159 + if (!evo) 1.160 + return NULL; 1.161 + 1.162 + TAILQ_INIT(&evo->buffer.callbacks); 1.163 + evo->buffer.refcnt = 1; 1.164 + evo->buffer.last_with_datap = &evo->buffer.first; 1.165 + 1.166 + evo->buffer.is_overlapped = 1; 1.167 + evo->fd = fd; 1.168 + 1.169 + return &evo->buffer; 1.170 +} 1.171 + 1.172 +int 1.173 +evbuffer_launch_write(struct evbuffer *buf, ev_ssize_t at_most, 1.174 + struct event_overlapped *ol) 1.175 +{ 1.176 + struct evbuffer_overlapped *buf_o = upcast_evbuffer(buf); 1.177 + int r = -1; 1.178 + int i; 1.179 + struct evbuffer_chain *chain; 1.180 + DWORD bytesSent; 1.181 + 1.182 + if (!buf) { 1.183 + /* No buffer, or it isn't overlapped */ 1.184 + return -1; 1.185 + } 1.186 + 1.187 + EVBUFFER_LOCK(buf); 1.188 + EVUTIL_ASSERT(!buf_o->read_in_progress); 1.189 + if (buf->freeze_start || buf_o->write_in_progress) 1.190 + goto done; 1.191 + if (!buf->total_len) { 1.192 + /* Nothing to write */ 1.193 + r = 0; 1.194 + goto done; 1.195 + } else if (at_most < 0 || (size_t)at_most > buf->total_len) { 1.196 + at_most = buf->total_len; 1.197 + } 1.198 + evbuffer_freeze(buf, 1); 1.199 + 1.200 + buf_o->first_pinned = NULL; 1.201 + buf_o->n_buffers = 0; 1.202 + memset(buf_o->buffers, 0, sizeof(buf_o->buffers)); 1.203 + 1.204 + chain = buf_o->first_pinned = buf->first; 1.205 + 1.206 + for (i=0; i < MAX_WSABUFS && chain; ++i, chain=chain->next) { 1.207 + WSABUF *b = &buf_o->buffers[i]; 1.208 + b->buf = (char*)( chain->buffer + chain->misalign ); 1.209 + _evbuffer_chain_pin(chain, EVBUFFER_MEM_PINNED_W); 1.210 + 1.211 + if ((size_t)at_most > chain->off) { 1.212 + /* XXXX Cast is safe for now, since win32 has no 1.213 + mmaped chains. But later, we need to have this 1.214 + add more WSAbufs if chain->off is greater than 1.215 + ULONG_MAX */ 1.216 + b->len = (unsigned long)chain->off; 1.217 + at_most -= chain->off; 1.218 + } else { 1.219 + b->len = (unsigned long)at_most; 1.220 + ++i; 1.221 + break; 1.222 + } 1.223 + } 1.224 + 1.225 + buf_o->n_buffers = i; 1.226 + _evbuffer_incref(buf); 1.227 + if (WSASend(buf_o->fd, buf_o->buffers, i, &bytesSent, 0, 1.228 + &ol->overlapped, NULL)) { 1.229 + int error = WSAGetLastError(); 1.230 + if (error != WSA_IO_PENDING) { 1.231 + /* An actual error. */ 1.232 + pin_release(buf_o, EVBUFFER_MEM_PINNED_W); 1.233 + evbuffer_unfreeze(buf, 1); 1.234 + evbuffer_free(buf); /* decref */ 1.235 + goto done; 1.236 + } 1.237 + } 1.238 + 1.239 + buf_o->write_in_progress = 1; 1.240 + r = 0; 1.241 +done: 1.242 + EVBUFFER_UNLOCK(buf); 1.243 + return r; 1.244 +} 1.245 + 1.246 +int 1.247 +evbuffer_launch_read(struct evbuffer *buf, size_t at_most, 1.248 + struct event_overlapped *ol) 1.249 +{ 1.250 + struct evbuffer_overlapped *buf_o = upcast_evbuffer(buf); 1.251 + int r = -1, i; 1.252 + int nvecs; 1.253 + int npin=0; 1.254 + struct evbuffer_chain *chain=NULL, **chainp; 1.255 + DWORD bytesRead; 1.256 + DWORD flags = 0; 1.257 + struct evbuffer_iovec vecs[MAX_WSABUFS]; 1.258 + 1.259 + if (!buf_o) 1.260 + return -1; 1.261 + EVBUFFER_LOCK(buf); 1.262 + EVUTIL_ASSERT(!buf_o->write_in_progress); 1.263 + if (buf->freeze_end || buf_o->read_in_progress) 1.264 + goto done; 1.265 + 1.266 + buf_o->first_pinned = NULL; 1.267 + buf_o->n_buffers = 0; 1.268 + memset(buf_o->buffers, 0, sizeof(buf_o->buffers)); 1.269 + 1.270 + if (_evbuffer_expand_fast(buf, at_most, MAX_WSABUFS) == -1) 1.271 + goto done; 1.272 + evbuffer_freeze(buf, 0); 1.273 + 1.274 + nvecs = _evbuffer_read_setup_vecs(buf, at_most, 1.275 + vecs, MAX_WSABUFS, &chainp, 1); 1.276 + for (i=0;i<nvecs;++i) { 1.277 + WSABUF_FROM_EVBUFFER_IOV( 1.278 + &buf_o->buffers[i], 1.279 + &vecs[i]); 1.280 + } 1.281 + 1.282 + buf_o->n_buffers = nvecs; 1.283 + buf_o->first_pinned = chain = *chainp; 1.284 + 1.285 + npin=0; 1.286 + for ( ; chain; chain = chain->next) { 1.287 + _evbuffer_chain_pin(chain, EVBUFFER_MEM_PINNED_R); 1.288 + ++npin; 1.289 + } 1.290 + EVUTIL_ASSERT(npin == nvecs); 1.291 + 1.292 + _evbuffer_incref(buf); 1.293 + if (WSARecv(buf_o->fd, buf_o->buffers, nvecs, &bytesRead, &flags, 1.294 + &ol->overlapped, NULL)) { 1.295 + int error = WSAGetLastError(); 1.296 + if (error != WSA_IO_PENDING) { 1.297 + /* An actual error. */ 1.298 + pin_release(buf_o, EVBUFFER_MEM_PINNED_R); 1.299 + evbuffer_unfreeze(buf, 0); 1.300 + evbuffer_free(buf); /* decref */ 1.301 + goto done; 1.302 + } 1.303 + } 1.304 + 1.305 + buf_o->read_in_progress = 1; 1.306 + r = 0; 1.307 +done: 1.308 + EVBUFFER_UNLOCK(buf); 1.309 + return r; 1.310 +} 1.311 + 1.312 +evutil_socket_t 1.313 +_evbuffer_overlapped_get_fd(struct evbuffer *buf) 1.314 +{ 1.315 + struct evbuffer_overlapped *buf_o = upcast_evbuffer(buf); 1.316 + return buf_o ? buf_o->fd : -1; 1.317 +} 1.318 + 1.319 +void 1.320 +_evbuffer_overlapped_set_fd(struct evbuffer *buf, evutil_socket_t fd) 1.321 +{ 1.322 + struct evbuffer_overlapped *buf_o = upcast_evbuffer(buf); 1.323 + EVBUFFER_LOCK(buf); 1.324 + /* XXX is this right?, should it cancel current I/O operations? */ 1.325 + if (buf_o) 1.326 + buf_o->fd = fd; 1.327 + EVBUFFER_UNLOCK(buf); 1.328 +}