other-licenses/android/ev_streams.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* $NetBSD: ev_streams.c,v 1.2 2004/05/20 19:52:31 christos Exp $ */
michael@0 2
michael@0 3 /*
michael@0 4 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
michael@0 5 * Copyright (c) 1996-1999 by Internet Software Consortium
michael@0 6 *
michael@0 7 * Permission to use, copy, modify, and distribute this software for any
michael@0 8 * purpose with or without fee is hereby granted, provided that the above
michael@0 9 * copyright notice and this permission notice appear in all copies.
michael@0 10 *
michael@0 11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
michael@0 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
michael@0 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
michael@0 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
michael@0 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
michael@0 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
michael@0 17 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
michael@0 18 */
michael@0 19
michael@0 20 /* ev_streams.c - implement asynch stream file IO for the eventlib
michael@0 21 * vix 04mar96 [initial]
michael@0 22 */
michael@0 23
michael@0 24 /*
michael@0 25 * This version of this file is derived from Android 2.3 "Gingerbread",
michael@0 26 * which contains uncredited changes by Android/Google developers. It has
michael@0 27 * been modified in 2011 for use in the Android build of Mozilla Firefox by
michael@0 28 * Mozilla contributors (including Michael Edwards <m.k.edwards@gmail.com>,
michael@0 29 * and Steve Workman <sjhworkman@gmail.com>).
michael@0 30 * These changes are offered under the same license as the original NetBSD
michael@0 31 * file, whose copyright and license are unchanged above.
michael@0 32 */
michael@0 33
michael@0 34 #define ANDROID_CHANGES 1
michael@0 35 #define MOZILLA_NECKO_EXCLUDE_CODE 1
michael@0 36
michael@0 37 #include <sys/cdefs.h>
michael@0 38 #if !defined(LINT) && !defined(CODECENTER) && !defined(lint)
michael@0 39 #ifdef notdef
michael@0 40 static const char rcsid[] = "Id: ev_streams.c,v 1.2.206.2 2004/03/17 00:29:51 marka Exp";
michael@0 41 #else
michael@0 42 __RCSID("$NetBSD: ev_streams.c,v 1.2 2004/05/20 19:52:31 christos Exp $");
michael@0 43 #endif
michael@0 44 #endif
michael@0 45
michael@0 46 #include <sys/types.h>
michael@0 47 #include <sys/uio.h>
michael@0 48
michael@0 49 #include <errno.h>
michael@0 50
michael@0 51 #include "eventlib.h"
michael@0 52 #include "eventlib_p.h"
michael@0 53
michael@0 54 #ifndef MOZILLA_NECKO_EXCLUDE_CODE
michael@0 55 #ifndef _LIBC
michael@0 56 static int copyvec(evStream *str, const struct iovec *iov, int iocnt);
michael@0 57 static void consume(evStream *str, size_t bytes);
michael@0 58 static void done(evContext opaqueCtx, evStream *str);
michael@0 59 static void writable(evContext opaqueCtx, void *uap, int fd, int evmask);
michael@0 60 static void readable(evContext opaqueCtx, void *uap, int fd, int evmask);
michael@0 61 #endif
michael@0 62 #endif
michael@0 63
michael@0 64 struct iovec
michael@0 65 evConsIovec(void *buf, size_t cnt) {
michael@0 66 struct iovec ret;
michael@0 67
michael@0 68 memset(&ret, 0xf5, sizeof ret);
michael@0 69 ret.iov_base = buf;
michael@0 70 ret.iov_len = cnt;
michael@0 71 return (ret);
michael@0 72 }
michael@0 73
michael@0 74 #ifndef MOZILLA_NECKO_EXCLUDE_CODE
michael@0 75 #ifndef _LIBC
michael@0 76 int
michael@0 77 evWrite(evContext opaqueCtx, int fd, const struct iovec *iov, int iocnt,
michael@0 78 evStreamFunc func, void *uap, evStreamID *id)
michael@0 79 {
michael@0 80 evContext_p *ctx = opaqueCtx.opaque;
michael@0 81 evStream *new;
michael@0 82 int save;
michael@0 83
michael@0 84 OKNEW(new);
michael@0 85 new->func = func;
michael@0 86 new->uap = uap;
michael@0 87 new->fd = fd;
michael@0 88 new->flags = 0;
michael@0 89 if (evSelectFD(opaqueCtx, fd, EV_WRITE, writable, new, &new->file) < 0)
michael@0 90 goto free;
michael@0 91 if (copyvec(new, iov, iocnt) < 0)
michael@0 92 goto free;
michael@0 93 new->prevDone = NULL;
michael@0 94 new->nextDone = NULL;
michael@0 95 if (ctx->streams != NULL)
michael@0 96 ctx->streams->prev = new;
michael@0 97 new->prev = NULL;
michael@0 98 new->next = ctx->streams;
michael@0 99 ctx->streams = new;
michael@0 100 if (id != NULL)
michael@0 101 id->opaque = new;
michael@0 102 return (0);
michael@0 103 free:
michael@0 104 save = errno;
michael@0 105 FREE(new);
michael@0 106 errno = save;
michael@0 107 return (-1);
michael@0 108 }
michael@0 109
michael@0 110 int
michael@0 111 evRead(evContext opaqueCtx, int fd, const struct iovec *iov, int iocnt,
michael@0 112 evStreamFunc func, void *uap, evStreamID *id)
michael@0 113 {
michael@0 114 evContext_p *ctx = opaqueCtx.opaque;
michael@0 115 evStream *new;
michael@0 116 int save;
michael@0 117
michael@0 118 OKNEW(new);
michael@0 119 new->func = func;
michael@0 120 new->uap = uap;
michael@0 121 new->fd = fd;
michael@0 122 new->flags = 0;
michael@0 123 if (evSelectFD(opaqueCtx, fd, EV_READ, readable, new, &new->file) < 0)
michael@0 124 goto free;
michael@0 125 if (copyvec(new, iov, iocnt) < 0)
michael@0 126 goto free;
michael@0 127 new->prevDone = NULL;
michael@0 128 new->nextDone = NULL;
michael@0 129 if (ctx->streams != NULL)
michael@0 130 ctx->streams->prev = new;
michael@0 131 new->prev = NULL;
michael@0 132 new->next = ctx->streams;
michael@0 133 ctx->streams = new;
michael@0 134 if (id)
michael@0 135 id->opaque = new;
michael@0 136 return (0);
michael@0 137 free:
michael@0 138 save = errno;
michael@0 139 FREE(new);
michael@0 140 errno = save;
michael@0 141 return (-1);
michael@0 142 }
michael@0 143
michael@0 144 int
michael@0 145 evTimeRW(evContext opaqueCtx, evStreamID id, evTimerID timer) /*ARGSUSED*/ {
michael@0 146 evStream *str = id.opaque;
michael@0 147
michael@0 148 UNUSED(opaqueCtx);
michael@0 149
michael@0 150 str->timer = timer;
michael@0 151 str->flags |= EV_STR_TIMEROK;
michael@0 152 return (0);
michael@0 153 }
michael@0 154
michael@0 155 int
michael@0 156 evUntimeRW(evContext opaqueCtx, evStreamID id) /*ARGSUSED*/ {
michael@0 157 evStream *str = id.opaque;
michael@0 158
michael@0 159 UNUSED(opaqueCtx);
michael@0 160
michael@0 161 str->flags &= ~EV_STR_TIMEROK;
michael@0 162 return (0);
michael@0 163 }
michael@0 164
michael@0 165 int
michael@0 166 evCancelRW(evContext opaqueCtx, evStreamID id) {
michael@0 167 evContext_p *ctx = opaqueCtx.opaque;
michael@0 168 evStream *old = id.opaque;
michael@0 169
michael@0 170 /*
michael@0 171 * The streams list is doubly threaded. First, there's ctx->streams
michael@0 172 * that's used by evDestroy() to find and cancel all streams. Second,
michael@0 173 * there's ctx->strDone (head) and ctx->strLast (tail) which thread
michael@0 174 * through the potentially smaller number of "IO completed" streams,
michael@0 175 * used in evGetNext() to avoid scanning the entire list.
michael@0 176 */
michael@0 177
michael@0 178 /* Unlink from ctx->streams. */
michael@0 179 if (old->prev != NULL)
michael@0 180 old->prev->next = old->next;
michael@0 181 else
michael@0 182 ctx->streams = old->next;
michael@0 183 if (old->next != NULL)
michael@0 184 old->next->prev = old->prev;
michael@0 185
michael@0 186 /*
michael@0 187 * If 'old' is on the ctx->strDone list, remove it. Update
michael@0 188 * ctx->strLast if necessary.
michael@0 189 */
michael@0 190 if (old->prevDone == NULL && old->nextDone == NULL) {
michael@0 191 /*
michael@0 192 * Either 'old' is the only item on the done list, or it's
michael@0 193 * not on the done list. If the former, then we unlink it
michael@0 194 * from the list. If the latter, we leave the list alone.
michael@0 195 */
michael@0 196 if (ctx->strDone == old) {
michael@0 197 ctx->strDone = NULL;
michael@0 198 ctx->strLast = NULL;
michael@0 199 }
michael@0 200 } else {
michael@0 201 if (old->prevDone != NULL)
michael@0 202 old->prevDone->nextDone = old->nextDone;
michael@0 203 else
michael@0 204 ctx->strDone = old->nextDone;
michael@0 205 if (old->nextDone != NULL)
michael@0 206 old->nextDone->prevDone = old->prevDone;
michael@0 207 else
michael@0 208 ctx->strLast = old->prevDone;
michael@0 209 }
michael@0 210
michael@0 211 /* Deallocate the stream. */
michael@0 212 if (old->file.opaque)
michael@0 213 evDeselectFD(opaqueCtx, old->file);
michael@0 214 memput(old->iovOrig, sizeof (struct iovec) * old->iovOrigCount);
michael@0 215 FREE(old);
michael@0 216 return (0);
michael@0 217 }
michael@0 218
michael@0 219 /* Copy a scatter/gather vector and initialize a stream handler's IO. */
michael@0 220 static int
michael@0 221 copyvec(evStream *str, const struct iovec *iov, int iocnt) {
michael@0 222 int i;
michael@0 223
michael@0 224 str->iovOrig = (struct iovec *)memget(sizeof(struct iovec) * iocnt);
michael@0 225 if (str->iovOrig == NULL) {
michael@0 226 errno = ENOMEM;
michael@0 227 return (-1);
michael@0 228 }
michael@0 229 str->ioTotal = 0;
michael@0 230 for (i = 0; i < iocnt; i++) {
michael@0 231 str->iovOrig[i] = iov[i];
michael@0 232 str->ioTotal += iov[i].iov_len;
michael@0 233 }
michael@0 234 str->iovOrigCount = iocnt;
michael@0 235 str->iovCur = str->iovOrig;
michael@0 236 str->iovCurCount = str->iovOrigCount;
michael@0 237 str->ioDone = 0;
michael@0 238 return (0);
michael@0 239 }
michael@0 240
michael@0 241 /* Pull off or truncate lead iovec(s). */
michael@0 242 static void
michael@0 243 consume(evStream *str, size_t bytes) {
michael@0 244 while (bytes > 0U) {
michael@0 245 if (bytes < (size_t)str->iovCur->iov_len) {
michael@0 246 str->iovCur->iov_len -= bytes;
michael@0 247 str->iovCur->iov_base = (void *)
michael@0 248 ((u_char *)str->iovCur->iov_base + bytes);
michael@0 249 str->ioDone += bytes;
michael@0 250 bytes = 0;
michael@0 251 } else {
michael@0 252 bytes -= str->iovCur->iov_len;
michael@0 253 str->ioDone += str->iovCur->iov_len;
michael@0 254 str->iovCur++;
michael@0 255 str->iovCurCount--;
michael@0 256 }
michael@0 257 }
michael@0 258 }
michael@0 259
michael@0 260 /* Add a stream to Done list and deselect the FD. */
michael@0 261 static void
michael@0 262 done(evContext opaqueCtx, evStream *str) {
michael@0 263 evContext_p *ctx = opaqueCtx.opaque;
michael@0 264
michael@0 265 if (ctx->strLast != NULL) {
michael@0 266 str->prevDone = ctx->strLast;
michael@0 267 ctx->strLast->nextDone = str;
michael@0 268 ctx->strLast = str;
michael@0 269 } else {
michael@0 270 INSIST(ctx->strDone == NULL);
michael@0 271 ctx->strDone = ctx->strLast = str;
michael@0 272 }
michael@0 273 evDeselectFD(opaqueCtx, str->file);
michael@0 274 str->file.opaque = NULL;
michael@0 275 /* evDrop() will call evCancelRW() on us. */
michael@0 276 }
michael@0 277
michael@0 278 /* Dribble out some bytes on the stream. (Called by evDispatch().) */
michael@0 279 static void
michael@0 280 writable(evContext opaqueCtx, void *uap, int fd, int evmask) {
michael@0 281 evStream *str = uap;
michael@0 282 int bytes;
michael@0 283
michael@0 284 UNUSED(evmask);
michael@0 285
michael@0 286 bytes = writev(fd, str->iovCur, str->iovCurCount);
michael@0 287 if (bytes > 0) {
michael@0 288 if ((str->flags & EV_STR_TIMEROK) != 0)
michael@0 289 evTouchIdleTimer(opaqueCtx, str->timer);
michael@0 290 consume(str, bytes);
michael@0 291 } else {
michael@0 292 if (bytes < 0 && errno != EINTR) {
michael@0 293 str->ioDone = -1;
michael@0 294 str->ioErrno = errno;
michael@0 295 }
michael@0 296 }
michael@0 297 if (str->ioDone == -1 || str->ioDone == str->ioTotal)
michael@0 298 done(opaqueCtx, str);
michael@0 299 }
michael@0 300
michael@0 301 /* Scoop up some bytes from the stream. (Called by evDispatch().) */
michael@0 302 static void
michael@0 303 readable(evContext opaqueCtx, void *uap, int fd, int evmask) {
michael@0 304 evStream *str = uap;
michael@0 305 int bytes;
michael@0 306
michael@0 307 UNUSED(evmask);
michael@0 308
michael@0 309 bytes = readv(fd, str->iovCur, str->iovCurCount);
michael@0 310 if (bytes > 0) {
michael@0 311 if ((str->flags & EV_STR_TIMEROK) != 0)
michael@0 312 evTouchIdleTimer(opaqueCtx, str->timer);
michael@0 313 consume(str, bytes);
michael@0 314 } else {
michael@0 315 if (bytes == 0)
michael@0 316 str->ioDone = 0;
michael@0 317 else {
michael@0 318 if (errno != EINTR) {
michael@0 319 str->ioDone = -1;
michael@0 320 str->ioErrno = errno;
michael@0 321 }
michael@0 322 }
michael@0 323 }
michael@0 324 if (str->ioDone <= 0 || str->ioDone == str->ioTotal)
michael@0 325 done(opaqueCtx, str);
michael@0 326 }
michael@0 327 #endif
michael@0 328 #endif

mercurial