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