ipc/chromium/src/third_party/libevent/bufferevent_pair.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/ipc/chromium/src/third_party/libevent/bufferevent_pair.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,333 @@
     1.4 +/*
     1.5 + * Copyright (c) 2009-2012 Niels Provos, 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 +#include <sys/types.h>
    1.31 +
    1.32 +#ifdef WIN32
    1.33 +#include <winsock2.h>
    1.34 +#endif
    1.35 +
    1.36 +#include "event2/event-config.h"
    1.37 +
    1.38 +#include "event2/util.h"
    1.39 +#include "event2/buffer.h"
    1.40 +#include "event2/bufferevent.h"
    1.41 +#include "event2/bufferevent_struct.h"
    1.42 +#include "event2/event.h"
    1.43 +#include "defer-internal.h"
    1.44 +#include "bufferevent-internal.h"
    1.45 +#include "mm-internal.h"
    1.46 +#include "util-internal.h"
    1.47 +
    1.48 +struct bufferevent_pair {
    1.49 +	struct bufferevent_private bev;
    1.50 +	struct bufferevent_pair *partner;
    1.51 +};
    1.52 +
    1.53 +
    1.54 +/* Given a bufferevent that's really a bev part of a bufferevent_pair,
    1.55 + * return that bufferevent_filtered. Returns NULL otherwise.*/
    1.56 +static inline struct bufferevent_pair *
    1.57 +upcast(struct bufferevent *bev)
    1.58 +{
    1.59 +	struct bufferevent_pair *bev_p;
    1.60 +	if (bev->be_ops != &bufferevent_ops_pair)
    1.61 +		return NULL;
    1.62 +	bev_p = EVUTIL_UPCAST(bev, struct bufferevent_pair, bev.bev);
    1.63 +	EVUTIL_ASSERT(bev_p->bev.bev.be_ops == &bufferevent_ops_pair);
    1.64 +	return bev_p;
    1.65 +}
    1.66 +
    1.67 +#define downcast(bev_pair) (&(bev_pair)->bev.bev)
    1.68 +
    1.69 +static inline void
    1.70 +incref_and_lock(struct bufferevent *b)
    1.71 +{
    1.72 +	struct bufferevent_pair *bevp;
    1.73 +	_bufferevent_incref_and_lock(b);
    1.74 +	bevp = upcast(b);
    1.75 +	if (bevp->partner)
    1.76 +		_bufferevent_incref_and_lock(downcast(bevp->partner));
    1.77 +}
    1.78 +
    1.79 +static inline void
    1.80 +decref_and_unlock(struct bufferevent *b)
    1.81 +{
    1.82 +	struct bufferevent_pair *bevp = upcast(b);
    1.83 +	if (bevp->partner)
    1.84 +		_bufferevent_decref_and_unlock(downcast(bevp->partner));
    1.85 +	_bufferevent_decref_and_unlock(b);
    1.86 +}
    1.87 +
    1.88 +/* XXX Handle close */
    1.89 +
    1.90 +static void be_pair_outbuf_cb(struct evbuffer *,
    1.91 +    const struct evbuffer_cb_info *, void *);
    1.92 +
    1.93 +static struct bufferevent_pair *
    1.94 +bufferevent_pair_elt_new(struct event_base *base,
    1.95 +    int options)
    1.96 +{
    1.97 +	struct bufferevent_pair *bufev;
    1.98 +	if (! (bufev = mm_calloc(1, sizeof(struct bufferevent_pair))))
    1.99 +		return NULL;
   1.100 +	if (bufferevent_init_common(&bufev->bev, base, &bufferevent_ops_pair,
   1.101 +		options)) {
   1.102 +		mm_free(bufev);
   1.103 +		return NULL;
   1.104 +	}
   1.105 +	if (!evbuffer_add_cb(bufev->bev.bev.output, be_pair_outbuf_cb, bufev)) {
   1.106 +		bufferevent_free(downcast(bufev));
   1.107 +		return NULL;
   1.108 +	}
   1.109 +
   1.110 +	_bufferevent_init_generic_timeout_cbs(&bufev->bev.bev);
   1.111 +
   1.112 +	return bufev;
   1.113 +}
   1.114 +
   1.115 +int
   1.116 +bufferevent_pair_new(struct event_base *base, int options,
   1.117 +    struct bufferevent *pair[2])
   1.118 +{
   1.119 +	struct bufferevent_pair *bufev1 = NULL, *bufev2 = NULL;
   1.120 +	int tmp_options;
   1.121 +
   1.122 +	options |= BEV_OPT_DEFER_CALLBACKS;
   1.123 +	tmp_options = options & ~BEV_OPT_THREADSAFE;
   1.124 +
   1.125 +	bufev1 = bufferevent_pair_elt_new(base, options);
   1.126 +	if (!bufev1)
   1.127 +		return -1;
   1.128 +	bufev2 = bufferevent_pair_elt_new(base, tmp_options);
   1.129 +	if (!bufev2) {
   1.130 +		bufferevent_free(downcast(bufev1));
   1.131 +		return -1;
   1.132 +	}
   1.133 +
   1.134 +	if (options & BEV_OPT_THREADSAFE) {
   1.135 +		/*XXXX check return */
   1.136 +		bufferevent_enable_locking(downcast(bufev2), bufev1->bev.lock);
   1.137 +	}
   1.138 +
   1.139 +	bufev1->partner = bufev2;
   1.140 +	bufev2->partner = bufev1;
   1.141 +
   1.142 +	evbuffer_freeze(downcast(bufev1)->input, 0);
   1.143 +	evbuffer_freeze(downcast(bufev1)->output, 1);
   1.144 +	evbuffer_freeze(downcast(bufev2)->input, 0);
   1.145 +	evbuffer_freeze(downcast(bufev2)->output, 1);
   1.146 +
   1.147 +	pair[0] = downcast(bufev1);
   1.148 +	pair[1] = downcast(bufev2);
   1.149 +
   1.150 +	return 0;
   1.151 +}
   1.152 +
   1.153 +static void
   1.154 +be_pair_transfer(struct bufferevent *src, struct bufferevent *dst,
   1.155 +    int ignore_wm)
   1.156 +{
   1.157 +	size_t src_size, dst_size;
   1.158 +	size_t n;
   1.159 +
   1.160 +	evbuffer_unfreeze(src->output, 1);
   1.161 +	evbuffer_unfreeze(dst->input, 0);
   1.162 +
   1.163 +	if (dst->wm_read.high) {
   1.164 +		dst_size = evbuffer_get_length(dst->input);
   1.165 +		if (dst_size < dst->wm_read.high) {
   1.166 +			n = dst->wm_read.high - dst_size;
   1.167 +			evbuffer_remove_buffer(src->output, dst->input, n);
   1.168 +		} else {
   1.169 +			if (!ignore_wm)
   1.170 +				goto done;
   1.171 +			n = evbuffer_get_length(src->output);
   1.172 +			evbuffer_add_buffer(dst->input, src->output);
   1.173 +		}
   1.174 +	} else {
   1.175 +		n = evbuffer_get_length(src->output);
   1.176 +		evbuffer_add_buffer(dst->input, src->output);
   1.177 +	}
   1.178 +
   1.179 +	if (n) {
   1.180 +		BEV_RESET_GENERIC_READ_TIMEOUT(dst);
   1.181 +
   1.182 +		if (evbuffer_get_length(dst->output))
   1.183 +			BEV_RESET_GENERIC_WRITE_TIMEOUT(dst);
   1.184 +		else
   1.185 +			BEV_DEL_GENERIC_WRITE_TIMEOUT(dst);
   1.186 +	}
   1.187 +
   1.188 +	src_size = evbuffer_get_length(src->output);
   1.189 +	dst_size = evbuffer_get_length(dst->input);
   1.190 +
   1.191 +	if (dst_size >= dst->wm_read.low) {
   1.192 +		_bufferevent_run_readcb(dst);
   1.193 +	}
   1.194 +	if (src_size <= src->wm_write.low) {
   1.195 +		_bufferevent_run_writecb(src);
   1.196 +	}
   1.197 +done:
   1.198 +	evbuffer_freeze(src->output, 1);
   1.199 +	evbuffer_freeze(dst->input, 0);
   1.200 +}
   1.201 +
   1.202 +static inline int
   1.203 +be_pair_wants_to_talk(struct bufferevent_pair *src,
   1.204 +    struct bufferevent_pair *dst)
   1.205 +{
   1.206 +	return (downcast(src)->enabled & EV_WRITE) &&
   1.207 +	    (downcast(dst)->enabled & EV_READ) &&
   1.208 +	    !dst->bev.read_suspended &&
   1.209 +	    evbuffer_get_length(downcast(src)->output);
   1.210 +}
   1.211 +
   1.212 +static void
   1.213 +be_pair_outbuf_cb(struct evbuffer *outbuf,
   1.214 +    const struct evbuffer_cb_info *info, void *arg)
   1.215 +{
   1.216 +	struct bufferevent_pair *bev_pair = arg;
   1.217 +	struct bufferevent_pair *partner = bev_pair->partner;
   1.218 +
   1.219 +	incref_and_lock(downcast(bev_pair));
   1.220 +
   1.221 +	if (info->n_added > info->n_deleted && partner) {
   1.222 +		/* We got more data.  If the other side's reading, then
   1.223 +		   hand it over. */
   1.224 +		if (be_pair_wants_to_talk(bev_pair, partner)) {
   1.225 +			be_pair_transfer(downcast(bev_pair), downcast(partner), 0);
   1.226 +		}
   1.227 +	}
   1.228 +
   1.229 +	decref_and_unlock(downcast(bev_pair));
   1.230 +}
   1.231 +
   1.232 +static int
   1.233 +be_pair_enable(struct bufferevent *bufev, short events)
   1.234 +{
   1.235 +	struct bufferevent_pair *bev_p = upcast(bufev);
   1.236 +	struct bufferevent_pair *partner = bev_p->partner;
   1.237 +
   1.238 +	incref_and_lock(bufev);
   1.239 +
   1.240 +	if (events & EV_READ) {
   1.241 +		BEV_RESET_GENERIC_READ_TIMEOUT(bufev);
   1.242 +	}
   1.243 +	if ((events & EV_WRITE) && evbuffer_get_length(bufev->output))
   1.244 +		BEV_RESET_GENERIC_WRITE_TIMEOUT(bufev);
   1.245 +
   1.246 +	/* We're starting to read! Does the other side have anything to write?*/
   1.247 +	if ((events & EV_READ) && partner &&
   1.248 +	    be_pair_wants_to_talk(partner, bev_p)) {
   1.249 +		be_pair_transfer(downcast(partner), bufev, 0);
   1.250 +	}
   1.251 +	/* We're starting to write! Does the other side want to read? */
   1.252 +	if ((events & EV_WRITE) && partner &&
   1.253 +	    be_pair_wants_to_talk(bev_p, partner)) {
   1.254 +		be_pair_transfer(bufev, downcast(partner), 0);
   1.255 +	}
   1.256 +	decref_and_unlock(bufev);
   1.257 +	return 0;
   1.258 +}
   1.259 +
   1.260 +static int
   1.261 +be_pair_disable(struct bufferevent *bev, short events)
   1.262 +{
   1.263 +	if (events & EV_READ) {
   1.264 +		BEV_DEL_GENERIC_READ_TIMEOUT(bev);
   1.265 +	}
   1.266 +	if (events & EV_WRITE)
   1.267 +		BEV_DEL_GENERIC_WRITE_TIMEOUT(bev);
   1.268 +	return 0;
   1.269 +}
   1.270 +
   1.271 +static void
   1.272 +be_pair_destruct(struct bufferevent *bev)
   1.273 +{
   1.274 +	struct bufferevent_pair *bev_p = upcast(bev);
   1.275 +
   1.276 +	if (bev_p->partner) {
   1.277 +		bev_p->partner->partner = NULL;
   1.278 +		bev_p->partner = NULL;
   1.279 +	}
   1.280 +
   1.281 +	_bufferevent_del_generic_timeout_cbs(bev);
   1.282 +}
   1.283 +
   1.284 +static int
   1.285 +be_pair_flush(struct bufferevent *bev, short iotype,
   1.286 +    enum bufferevent_flush_mode mode)
   1.287 +{
   1.288 +	struct bufferevent_pair *bev_p = upcast(bev);
   1.289 +	struct bufferevent *partner;
   1.290 +	incref_and_lock(bev);
   1.291 +	if (!bev_p->partner)
   1.292 +		return -1;
   1.293 +
   1.294 +	partner = downcast(bev_p->partner);
   1.295 +
   1.296 +	if (mode == BEV_NORMAL)
   1.297 +		return 0;
   1.298 +
   1.299 +	if ((iotype & EV_READ) != 0)
   1.300 +		be_pair_transfer(partner, bev, 1);
   1.301 +
   1.302 +	if ((iotype & EV_WRITE) != 0)
   1.303 +		be_pair_transfer(bev, partner, 1);
   1.304 +
   1.305 +	if (mode == BEV_FINISHED) {
   1.306 +		_bufferevent_run_eventcb(partner, iotype|BEV_EVENT_EOF);
   1.307 +	}
   1.308 +	decref_and_unlock(bev);
   1.309 +	return 0;
   1.310 +}
   1.311 +
   1.312 +struct bufferevent *
   1.313 +bufferevent_pair_get_partner(struct bufferevent *bev)
   1.314 +{
   1.315 +	struct bufferevent_pair *bev_p;
   1.316 +	struct bufferevent *partner;
   1.317 +	bev_p = upcast(bev);
   1.318 +	if (! bev_p)
   1.319 +		return NULL;
   1.320 +
   1.321 +	incref_and_lock(bev);
   1.322 +	partner = downcast(bev_p->partner);
   1.323 +	decref_and_unlock(bev);
   1.324 +	return partner;
   1.325 +}
   1.326 +
   1.327 +const struct bufferevent_ops bufferevent_ops_pair = {
   1.328 +	"pair_elt",
   1.329 +	evutil_offsetof(struct bufferevent_pair, bev.bev),
   1.330 +	be_pair_enable,
   1.331 +	be_pair_disable,
   1.332 +	be_pair_destruct,
   1.333 +	_bufferevent_generic_adj_timeouts,
   1.334 +	be_pair_flush,
   1.335 +	NULL, /* ctrl */
   1.336 +};

mercurial