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