other-licenses/android/ev_streams.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/other-licenses/android/ev_streams.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,328 @@
     1.4 +/*	$NetBSD: ev_streams.c,v 1.2 2004/05/20 19:52:31 christos Exp $	*/
     1.5 +
     1.6 +/*
     1.7 + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
     1.8 + * Copyright (c) 1996-1999 by Internet Software Consortium
     1.9 + *
    1.10 + * Permission to use, copy, modify, and distribute this software for any
    1.11 + * purpose with or without fee is hereby granted, provided that the above
    1.12 + * copyright notice and this permission notice appear in all copies.
    1.13 + *
    1.14 + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
    1.15 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    1.16 + * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
    1.17 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    1.18 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    1.19 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
    1.20 + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    1.21 + */
    1.22 +
    1.23 +/* ev_streams.c - implement asynch stream file IO for the eventlib
    1.24 + * vix 04mar96 [initial]
    1.25 + */
    1.26 +
    1.27 +/*
    1.28 + * This version of this file is derived from Android 2.3 "Gingerbread",
    1.29 + * which contains uncredited changes by Android/Google developers.  It has
    1.30 + * been modified in 2011 for use in the Android build of Mozilla Firefox by
    1.31 + * Mozilla contributors (including Michael Edwards <m.k.edwards@gmail.com>,
    1.32 + * and Steve Workman <sjhworkman@gmail.com>).
    1.33 + * These changes are offered under the same license as the original NetBSD
    1.34 + * file, whose copyright and license are unchanged above.
    1.35 + */
    1.36 +
    1.37 +#define ANDROID_CHANGES 1
    1.38 +#define MOZILLA_NECKO_EXCLUDE_CODE 1
    1.39 +
    1.40 +#include <sys/cdefs.h>
    1.41 +#if !defined(LINT) && !defined(CODECENTER) && !defined(lint)
    1.42 +#ifdef notdef
    1.43 +static const char rcsid[] = "Id: ev_streams.c,v 1.2.206.2 2004/03/17 00:29:51 marka Exp";
    1.44 +#else
    1.45 +__RCSID("$NetBSD: ev_streams.c,v 1.2 2004/05/20 19:52:31 christos Exp $");
    1.46 +#endif
    1.47 +#endif
    1.48 +
    1.49 +#include <sys/types.h>
    1.50 +#include <sys/uio.h>
    1.51 +
    1.52 +#include <errno.h>
    1.53 +
    1.54 +#include "eventlib.h"
    1.55 +#include "eventlib_p.h"
    1.56 +
    1.57 +#ifndef MOZILLA_NECKO_EXCLUDE_CODE
    1.58 +#ifndef _LIBC
    1.59 +static int	copyvec(evStream *str, const struct iovec *iov, int iocnt);
    1.60 +static void	consume(evStream *str, size_t bytes);
    1.61 +static void	done(evContext opaqueCtx, evStream *str);
    1.62 +static void	writable(evContext opaqueCtx, void *uap, int fd, int evmask);
    1.63 +static void	readable(evContext opaqueCtx, void *uap, int fd, int evmask);
    1.64 +#endif
    1.65 +#endif
    1.66 +
    1.67 +struct iovec
    1.68 +evConsIovec(void *buf, size_t cnt) {
    1.69 +	struct iovec ret;
    1.70 +
    1.71 +	memset(&ret, 0xf5, sizeof ret);
    1.72 +	ret.iov_base = buf;
    1.73 +	ret.iov_len = cnt;
    1.74 +	return (ret);
    1.75 +}
    1.76 +
    1.77 +#ifndef MOZILLA_NECKO_EXCLUDE_CODE
    1.78 +#ifndef _LIBC
    1.79 +int
    1.80 +evWrite(evContext opaqueCtx, int fd, const struct iovec *iov, int iocnt,
    1.81 +	evStreamFunc func, void *uap, evStreamID *id)
    1.82 +{
    1.83 +	evContext_p *ctx = opaqueCtx.opaque;
    1.84 +	evStream *new;
    1.85 +	int save;
    1.86 +
    1.87 +	OKNEW(new);
    1.88 +	new->func = func;
    1.89 +	new->uap = uap;
    1.90 +	new->fd = fd;
    1.91 +	new->flags = 0;
    1.92 +	if (evSelectFD(opaqueCtx, fd, EV_WRITE, writable, new, &new->file) < 0)
    1.93 +		goto free;
    1.94 +	if (copyvec(new, iov, iocnt) < 0)
    1.95 +		goto free;
    1.96 +	new->prevDone = NULL;
    1.97 +	new->nextDone = NULL;
    1.98 +	if (ctx->streams != NULL)
    1.99 +		ctx->streams->prev = new;
   1.100 +	new->prev = NULL;
   1.101 +	new->next = ctx->streams;
   1.102 +	ctx->streams = new;
   1.103 +	if (id != NULL)
   1.104 +		id->opaque = new;
   1.105 +	return (0);
   1.106 + free:
   1.107 +	save = errno;
   1.108 +	FREE(new);
   1.109 +	errno = save;
   1.110 +	return (-1);
   1.111 +}
   1.112 +
   1.113 +int
   1.114 +evRead(evContext opaqueCtx, int fd, const struct iovec *iov, int iocnt,
   1.115 +       evStreamFunc func, void *uap, evStreamID *id)
   1.116 +{
   1.117 +	evContext_p *ctx = opaqueCtx.opaque;
   1.118 +	evStream *new;
   1.119 +	int save;
   1.120 +
   1.121 +	OKNEW(new);
   1.122 +	new->func = func;
   1.123 +	new->uap = uap;
   1.124 +	new->fd = fd;
   1.125 +	new->flags = 0;
   1.126 +	if (evSelectFD(opaqueCtx, fd, EV_READ, readable, new, &new->file) < 0)
   1.127 +		goto free;
   1.128 +	if (copyvec(new, iov, iocnt) < 0)
   1.129 +		goto free;
   1.130 +	new->prevDone = NULL;
   1.131 +	new->nextDone = NULL;
   1.132 +	if (ctx->streams != NULL)
   1.133 +		ctx->streams->prev = new;
   1.134 +	new->prev = NULL;
   1.135 +	new->next = ctx->streams;
   1.136 +	ctx->streams = new;
   1.137 +	if (id)
   1.138 +		id->opaque = new;
   1.139 +	return (0);
   1.140 + free:
   1.141 +	save = errno;
   1.142 +	FREE(new);
   1.143 +	errno = save;
   1.144 +	return (-1);
   1.145 +}
   1.146 +
   1.147 +int
   1.148 +evTimeRW(evContext opaqueCtx, evStreamID id, evTimerID timer) /*ARGSUSED*/ {
   1.149 +	evStream *str = id.opaque;
   1.150 +
   1.151 +	UNUSED(opaqueCtx);
   1.152 +
   1.153 +	str->timer = timer;
   1.154 +	str->flags |= EV_STR_TIMEROK;
   1.155 +	return (0);
   1.156 +}
   1.157 +
   1.158 +int
   1.159 +evUntimeRW(evContext opaqueCtx, evStreamID id) /*ARGSUSED*/ {
   1.160 +	evStream *str = id.opaque;
   1.161 +
   1.162 +	UNUSED(opaqueCtx);
   1.163 +
   1.164 +	str->flags &= ~EV_STR_TIMEROK;
   1.165 +	return (0);
   1.166 +}
   1.167 +
   1.168 +int
   1.169 +evCancelRW(evContext opaqueCtx, evStreamID id) {
   1.170 +	evContext_p *ctx = opaqueCtx.opaque;
   1.171 +	evStream *old = id.opaque;
   1.172 +
   1.173 +	/*
   1.174 +	 * The streams list is doubly threaded.  First, there's ctx->streams
   1.175 +	 * that's used by evDestroy() to find and cancel all streams.  Second,
   1.176 +	 * there's ctx->strDone (head) and ctx->strLast (tail) which thread
   1.177 +	 * through the potentially smaller number of "IO completed" streams,
   1.178 +	 * used in evGetNext() to avoid scanning the entire list.
   1.179 +	 */
   1.180 +
   1.181 +	/* Unlink from ctx->streams. */
   1.182 +	if (old->prev != NULL)
   1.183 +		old->prev->next = old->next;
   1.184 +	else
   1.185 +		ctx->streams = old->next;
   1.186 +	if (old->next != NULL)
   1.187 +		old->next->prev = old->prev;
   1.188 +
   1.189 +	/*
   1.190 +	 * If 'old' is on the ctx->strDone list, remove it.  Update
   1.191 +	 * ctx->strLast if necessary.
   1.192 +	 */
   1.193 +	if (old->prevDone == NULL && old->nextDone == NULL) {
   1.194 +		/*
   1.195 +		 * Either 'old' is the only item on the done list, or it's
   1.196 +		 * not on the done list.  If the former, then we unlink it
   1.197 +		 * from the list.  If the latter, we leave the list alone.
   1.198 +		 */
   1.199 +		if (ctx->strDone == old) {
   1.200 +			ctx->strDone = NULL;
   1.201 +			ctx->strLast = NULL;
   1.202 +		}
   1.203 +	} else {
   1.204 +		if (old->prevDone != NULL)
   1.205 +			old->prevDone->nextDone = old->nextDone;
   1.206 +		else
   1.207 +			ctx->strDone = old->nextDone;
   1.208 +		if (old->nextDone != NULL)
   1.209 +			old->nextDone->prevDone = old->prevDone;
   1.210 +		else
   1.211 +			ctx->strLast = old->prevDone;
   1.212 +	}
   1.213 +
   1.214 +	/* Deallocate the stream. */
   1.215 +	if (old->file.opaque)
   1.216 +		evDeselectFD(opaqueCtx, old->file);
   1.217 +	memput(old->iovOrig, sizeof (struct iovec) * old->iovOrigCount);
   1.218 +	FREE(old);
   1.219 +	return (0);
   1.220 +}
   1.221 +
   1.222 +/* Copy a scatter/gather vector and initialize a stream handler's IO. */
   1.223 +static int
   1.224 +copyvec(evStream *str, const struct iovec *iov, int iocnt) {
   1.225 +	int i;
   1.226 +
   1.227 +	str->iovOrig = (struct iovec *)memget(sizeof(struct iovec) * iocnt);
   1.228 +	if (str->iovOrig == NULL) {
   1.229 +		errno = ENOMEM;
   1.230 +		return (-1);
   1.231 +	}
   1.232 +	str->ioTotal = 0;
   1.233 +	for (i = 0; i < iocnt; i++) {
   1.234 +		str->iovOrig[i] = iov[i];
   1.235 +		str->ioTotal += iov[i].iov_len;
   1.236 +	}
   1.237 +	str->iovOrigCount = iocnt;
   1.238 +	str->iovCur = str->iovOrig;
   1.239 +	str->iovCurCount = str->iovOrigCount;
   1.240 +	str->ioDone = 0;
   1.241 +	return (0);
   1.242 +}
   1.243 +
   1.244 +/* Pull off or truncate lead iovec(s). */
   1.245 +static void
   1.246 +consume(evStream *str, size_t bytes) {
   1.247 +	while (bytes > 0U) {
   1.248 +		if (bytes < (size_t)str->iovCur->iov_len) {
   1.249 +			str->iovCur->iov_len -= bytes;
   1.250 +			str->iovCur->iov_base = (void *)
   1.251 +				((u_char *)str->iovCur->iov_base + bytes);
   1.252 +			str->ioDone += bytes;
   1.253 +			bytes = 0;
   1.254 +		} else {
   1.255 +			bytes -= str->iovCur->iov_len;
   1.256 +			str->ioDone += str->iovCur->iov_len;
   1.257 +			str->iovCur++;
   1.258 +			str->iovCurCount--;
   1.259 +		}
   1.260 +	}
   1.261 +}
   1.262 +
   1.263 +/* Add a stream to Done list and deselect the FD. */
   1.264 +static void
   1.265 +done(evContext opaqueCtx, evStream *str) {
   1.266 +	evContext_p *ctx = opaqueCtx.opaque;
   1.267 +
   1.268 +	if (ctx->strLast != NULL) {
   1.269 +		str->prevDone = ctx->strLast;
   1.270 +		ctx->strLast->nextDone = str;
   1.271 +		ctx->strLast = str;
   1.272 +	} else {
   1.273 +		INSIST(ctx->strDone == NULL);
   1.274 +		ctx->strDone = ctx->strLast = str;
   1.275 +	}
   1.276 +	evDeselectFD(opaqueCtx, str->file);
   1.277 +	str->file.opaque = NULL;
   1.278 +	/* evDrop() will call evCancelRW() on us. */
   1.279 +}
   1.280 +
   1.281 +/* Dribble out some bytes on the stream.  (Called by evDispatch().) */
   1.282 +static void
   1.283 +writable(evContext opaqueCtx, void *uap, int fd, int evmask) {
   1.284 +	evStream *str = uap;
   1.285 +	int bytes;
   1.286 +
   1.287 +	UNUSED(evmask);
   1.288 +
   1.289 +	bytes = writev(fd, str->iovCur, str->iovCurCount);
   1.290 +	if (bytes > 0) {
   1.291 +		if ((str->flags & EV_STR_TIMEROK) != 0)
   1.292 +			evTouchIdleTimer(opaqueCtx, str->timer);
   1.293 +		consume(str, bytes);
   1.294 +	} else {
   1.295 +		if (bytes < 0 && errno != EINTR) {
   1.296 +			str->ioDone = -1;
   1.297 +			str->ioErrno = errno;
   1.298 +		}
   1.299 +	}
   1.300 +	if (str->ioDone == -1 || str->ioDone == str->ioTotal)
   1.301 +		done(opaqueCtx, str);
   1.302 +}
   1.303 +
   1.304 +/* Scoop up some bytes from the stream.  (Called by evDispatch().) */
   1.305 +static void
   1.306 +readable(evContext opaqueCtx, void *uap, int fd, int evmask) {
   1.307 +	evStream *str = uap;
   1.308 +	int bytes;
   1.309 +
   1.310 +	UNUSED(evmask);
   1.311 +
   1.312 +	bytes = readv(fd, str->iovCur, str->iovCurCount);
   1.313 +	if (bytes > 0) {
   1.314 +		if ((str->flags & EV_STR_TIMEROK) != 0)
   1.315 +			evTouchIdleTimer(opaqueCtx, str->timer);
   1.316 +		consume(str, bytes);
   1.317 +	} else {
   1.318 +		if (bytes == 0)
   1.319 +			str->ioDone = 0;
   1.320 +		else {
   1.321 +			if (errno != EINTR) {
   1.322 +				str->ioDone = -1;
   1.323 +				str->ioErrno = errno;
   1.324 +			}
   1.325 +		}
   1.326 +	}
   1.327 +	if (str->ioDone <= 0 || str->ioDone == str->ioTotal)
   1.328 +		done(opaqueCtx, str);
   1.329 +}
   1.330 +#endif
   1.331 +#endif

mercurial