xref: /onnv-gate/usr/src/lib/libresolv2/common/isc/ev_streams.c (revision 11038:74b12212b8a2)
10Sstevel@tonic-gate /*
2*11038SRao.Shoaib@Sun.COM  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3*11038SRao.Shoaib@Sun.COM  * Copyright (c) 1996-1999 by Internet Software Consortium
40Sstevel@tonic-gate  *
50Sstevel@tonic-gate  * Permission to use, copy, modify, and distribute this software for any
60Sstevel@tonic-gate  * purpose with or without fee is hereby granted, provided that the above
70Sstevel@tonic-gate  * copyright notice and this permission notice appear in all copies.
80Sstevel@tonic-gate  *
9*11038SRao.Shoaib@Sun.COM  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10*11038SRao.Shoaib@Sun.COM  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11*11038SRao.Shoaib@Sun.COM  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
12*11038SRao.Shoaib@Sun.COM  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13*11038SRao.Shoaib@Sun.COM  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14*11038SRao.Shoaib@Sun.COM  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15*11038SRao.Shoaib@Sun.COM  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
160Sstevel@tonic-gate  */
170Sstevel@tonic-gate 
180Sstevel@tonic-gate /* ev_streams.c - implement asynch stream file IO for the eventlib
190Sstevel@tonic-gate  * vix 04mar96 [initial]
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate 
220Sstevel@tonic-gate #if !defined(LINT) && !defined(CODECENTER)
23*11038SRao.Shoaib@Sun.COM static const char rcsid[] = "$Id: ev_streams.c,v 1.5 2005/04/27 04:56:36 sra Exp $";
240Sstevel@tonic-gate #endif
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include "port_before.h"
270Sstevel@tonic-gate #include "fd_setsize.h"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <sys/types.h>
300Sstevel@tonic-gate #include <sys/uio.h>
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #include <errno.h>
330Sstevel@tonic-gate 
340Sstevel@tonic-gate #include <isc/eventlib.h>
350Sstevel@tonic-gate #include <isc/assertions.h>
360Sstevel@tonic-gate #include "eventlib_p.h"
370Sstevel@tonic-gate 
380Sstevel@tonic-gate #include "port_after.h"
390Sstevel@tonic-gate 
400Sstevel@tonic-gate static int	copyvec(evStream *str, const struct iovec *iov, int iocnt);
410Sstevel@tonic-gate static void	consume(evStream *str, size_t bytes);
420Sstevel@tonic-gate static void	done(evContext opaqueCtx, evStream *str);
430Sstevel@tonic-gate static void	writable(evContext opaqueCtx, void *uap, int fd, int evmask);
440Sstevel@tonic-gate static void	readable(evContext opaqueCtx, void *uap, int fd, int evmask);
450Sstevel@tonic-gate 
460Sstevel@tonic-gate struct iovec
evConsIovec(void * buf,size_t cnt)470Sstevel@tonic-gate evConsIovec(void *buf, size_t cnt) {
480Sstevel@tonic-gate 	struct iovec ret;
490Sstevel@tonic-gate 
500Sstevel@tonic-gate 	memset(&ret, 0xf5, sizeof ret);
510Sstevel@tonic-gate 	ret.iov_base = buf;
520Sstevel@tonic-gate 	ret.iov_len = cnt;
530Sstevel@tonic-gate 	return (ret);
540Sstevel@tonic-gate }
550Sstevel@tonic-gate 
560Sstevel@tonic-gate int
evWrite(evContext opaqueCtx,int fd,const struct iovec * iov,int iocnt,evStreamFunc func,void * uap,evStreamID * id)570Sstevel@tonic-gate evWrite(evContext opaqueCtx, int fd, const struct iovec *iov, int iocnt,
580Sstevel@tonic-gate 	evStreamFunc func, void *uap, evStreamID *id)
590Sstevel@tonic-gate {
600Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
610Sstevel@tonic-gate 	evStream *new;
620Sstevel@tonic-gate 	int save;
630Sstevel@tonic-gate 
640Sstevel@tonic-gate 	OKNEW(new);
650Sstevel@tonic-gate 	new->func = func;
660Sstevel@tonic-gate 	new->uap = uap;
670Sstevel@tonic-gate 	new->fd = fd;
680Sstevel@tonic-gate 	new->flags = 0;
690Sstevel@tonic-gate 	if (evSelectFD(opaqueCtx, fd, EV_WRITE, writable, new, &new->file) < 0)
700Sstevel@tonic-gate 		goto free;
710Sstevel@tonic-gate 	if (copyvec(new, iov, iocnt) < 0)
720Sstevel@tonic-gate 		goto free;
730Sstevel@tonic-gate 	new->prevDone = NULL;
740Sstevel@tonic-gate 	new->nextDone = NULL;
750Sstevel@tonic-gate 	if (ctx->streams != NULL)
760Sstevel@tonic-gate 		ctx->streams->prev = new;
770Sstevel@tonic-gate 	new->prev = NULL;
780Sstevel@tonic-gate 	new->next = ctx->streams;
790Sstevel@tonic-gate 	ctx->streams = new;
800Sstevel@tonic-gate 	if (id != NULL)
810Sstevel@tonic-gate 		id->opaque = new;
820Sstevel@tonic-gate 	return (0);
830Sstevel@tonic-gate  free:
840Sstevel@tonic-gate 	save = errno;
850Sstevel@tonic-gate 	FREE(new);
860Sstevel@tonic-gate 	errno = save;
870Sstevel@tonic-gate 	return (-1);
880Sstevel@tonic-gate }
890Sstevel@tonic-gate 
900Sstevel@tonic-gate int
evRead(evContext opaqueCtx,int fd,const struct iovec * iov,int iocnt,evStreamFunc func,void * uap,evStreamID * id)910Sstevel@tonic-gate evRead(evContext opaqueCtx, int fd, const struct iovec *iov, int iocnt,
920Sstevel@tonic-gate        evStreamFunc func, void *uap, evStreamID *id)
930Sstevel@tonic-gate {
940Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
950Sstevel@tonic-gate 	evStream *new;
960Sstevel@tonic-gate 	int save;
970Sstevel@tonic-gate 
980Sstevel@tonic-gate 	OKNEW(new);
990Sstevel@tonic-gate 	new->func = func;
1000Sstevel@tonic-gate 	new->uap = uap;
1010Sstevel@tonic-gate 	new->fd = fd;
1020Sstevel@tonic-gate 	new->flags = 0;
1030Sstevel@tonic-gate 	if (evSelectFD(opaqueCtx, fd, EV_READ, readable, new, &new->file) < 0)
1040Sstevel@tonic-gate 		goto free;
1050Sstevel@tonic-gate 	if (copyvec(new, iov, iocnt) < 0)
1060Sstevel@tonic-gate 		goto free;
1070Sstevel@tonic-gate 	new->prevDone = NULL;
1080Sstevel@tonic-gate 	new->nextDone = NULL;
1090Sstevel@tonic-gate 	if (ctx->streams != NULL)
1100Sstevel@tonic-gate 		ctx->streams->prev = new;
1110Sstevel@tonic-gate 	new->prev = NULL;
1120Sstevel@tonic-gate 	new->next = ctx->streams;
1130Sstevel@tonic-gate 	ctx->streams = new;
1140Sstevel@tonic-gate 	if (id)
1150Sstevel@tonic-gate 		id->opaque = new;
1160Sstevel@tonic-gate 	return (0);
1170Sstevel@tonic-gate  free:
1180Sstevel@tonic-gate 	save = errno;
1190Sstevel@tonic-gate 	FREE(new);
1200Sstevel@tonic-gate 	errno = save;
1210Sstevel@tonic-gate 	return (-1);
1220Sstevel@tonic-gate }
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate int
evTimeRW(evContext opaqueCtx,evStreamID id,evTimerID timer)1250Sstevel@tonic-gate evTimeRW(evContext opaqueCtx, evStreamID id, evTimerID timer) /*ARGSUSED*/ {
1260Sstevel@tonic-gate 	evStream *str = id.opaque;
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate 	UNUSED(opaqueCtx);
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate 	str->timer = timer;
1310Sstevel@tonic-gate 	str->flags |= EV_STR_TIMEROK;
1320Sstevel@tonic-gate 	return (0);
1330Sstevel@tonic-gate }
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate int
evUntimeRW(evContext opaqueCtx,evStreamID id)1360Sstevel@tonic-gate evUntimeRW(evContext opaqueCtx, evStreamID id) /*ARGSUSED*/ {
1370Sstevel@tonic-gate 	evStream *str = id.opaque;
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate 	UNUSED(opaqueCtx);
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate 	str->flags &= ~EV_STR_TIMEROK;
1420Sstevel@tonic-gate 	return (0);
1430Sstevel@tonic-gate }
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate int
evCancelRW(evContext opaqueCtx,evStreamID id)1460Sstevel@tonic-gate evCancelRW(evContext opaqueCtx, evStreamID id) {
1470Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
1480Sstevel@tonic-gate 	evStream *old = id.opaque;
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate 	/*
1510Sstevel@tonic-gate 	 * The streams list is doubly threaded.  First, there's ctx->streams
1520Sstevel@tonic-gate 	 * that's used by evDestroy() to find and cancel all streams.  Second,
1530Sstevel@tonic-gate 	 * there's ctx->strDone (head) and ctx->strLast (tail) which thread
1540Sstevel@tonic-gate 	 * through the potentially smaller number of "IO completed" streams,
1550Sstevel@tonic-gate 	 * used in evGetNext() to avoid scanning the entire list.
1560Sstevel@tonic-gate 	 */
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate 	/* Unlink from ctx->streams. */
1590Sstevel@tonic-gate 	if (old->prev != NULL)
1600Sstevel@tonic-gate 		old->prev->next = old->next;
1610Sstevel@tonic-gate 	else
1620Sstevel@tonic-gate 		ctx->streams = old->next;
1630Sstevel@tonic-gate 	if (old->next != NULL)
1640Sstevel@tonic-gate 		old->next->prev = old->prev;
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate 	/*
1670Sstevel@tonic-gate 	 * If 'old' is on the ctx->strDone list, remove it.  Update
1680Sstevel@tonic-gate 	 * ctx->strLast if necessary.
1690Sstevel@tonic-gate 	 */
1700Sstevel@tonic-gate 	if (old->prevDone == NULL && old->nextDone == NULL) {
1710Sstevel@tonic-gate 		/*
1720Sstevel@tonic-gate 		 * Either 'old' is the only item on the done list, or it's
1730Sstevel@tonic-gate 		 * not on the done list.  If the former, then we unlink it
1740Sstevel@tonic-gate 		 * from the list.  If the latter, we leave the list alone.
1750Sstevel@tonic-gate 		 */
1760Sstevel@tonic-gate 		if (ctx->strDone == old) {
1770Sstevel@tonic-gate 			ctx->strDone = NULL;
1780Sstevel@tonic-gate 			ctx->strLast = NULL;
1790Sstevel@tonic-gate 		}
1800Sstevel@tonic-gate 	} else {
1810Sstevel@tonic-gate 		if (old->prevDone != NULL)
1820Sstevel@tonic-gate 			old->prevDone->nextDone = old->nextDone;
1830Sstevel@tonic-gate 		else
1840Sstevel@tonic-gate 			ctx->strDone = old->nextDone;
1850Sstevel@tonic-gate 		if (old->nextDone != NULL)
1860Sstevel@tonic-gate 			old->nextDone->prevDone = old->prevDone;
1870Sstevel@tonic-gate 		else
1880Sstevel@tonic-gate 			ctx->strLast = old->prevDone;
1890Sstevel@tonic-gate 	}
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate 	/* Deallocate the stream. */
1920Sstevel@tonic-gate 	if (old->file.opaque)
1930Sstevel@tonic-gate 		evDeselectFD(opaqueCtx, old->file);
1940Sstevel@tonic-gate 	memput(old->iovOrig, sizeof (struct iovec) * old->iovOrigCount);
1950Sstevel@tonic-gate 	FREE(old);
1960Sstevel@tonic-gate 	return (0);
1970Sstevel@tonic-gate }
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate /* Copy a scatter/gather vector and initialize a stream handler's IO. */
2000Sstevel@tonic-gate static int
copyvec(evStream * str,const struct iovec * iov,int iocnt)2010Sstevel@tonic-gate copyvec(evStream *str, const struct iovec *iov, int iocnt) {
2020Sstevel@tonic-gate 	int i;
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 	str->iovOrig = (struct iovec *)memget(sizeof(struct iovec) * iocnt);
2050Sstevel@tonic-gate 	if (str->iovOrig == NULL) {
2060Sstevel@tonic-gate 		errno = ENOMEM;
2070Sstevel@tonic-gate 		return (-1);
2080Sstevel@tonic-gate 	}
2090Sstevel@tonic-gate 	str->ioTotal = 0;
2100Sstevel@tonic-gate 	for (i = 0; i < iocnt; i++) {
2110Sstevel@tonic-gate 		str->iovOrig[i] = iov[i];
2120Sstevel@tonic-gate 		str->ioTotal += iov[i].iov_len;
2130Sstevel@tonic-gate 	}
2140Sstevel@tonic-gate 	str->iovOrigCount = iocnt;
2150Sstevel@tonic-gate 	str->iovCur = str->iovOrig;
2160Sstevel@tonic-gate 	str->iovCurCount = str->iovOrigCount;
2170Sstevel@tonic-gate 	str->ioDone = 0;
2180Sstevel@tonic-gate 	return (0);
2190Sstevel@tonic-gate }
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate /* Pull off or truncate lead iovec(s). */
2220Sstevel@tonic-gate static void
consume(evStream * str,size_t bytes)2230Sstevel@tonic-gate consume(evStream *str, size_t bytes) {
224*11038SRao.Shoaib@Sun.COM 	while (bytes > 0U) {
2250Sstevel@tonic-gate 		if (bytes < (size_t)str->iovCur->iov_len) {
2260Sstevel@tonic-gate 			str->iovCur->iov_len -= bytes;
2270Sstevel@tonic-gate 			str->iovCur->iov_base = (void *)
2280Sstevel@tonic-gate 				((u_char *)str->iovCur->iov_base + bytes);
2290Sstevel@tonic-gate 			str->ioDone += bytes;
2300Sstevel@tonic-gate 			bytes = 0;
2310Sstevel@tonic-gate 		} else {
2320Sstevel@tonic-gate 			bytes -= str->iovCur->iov_len;
2330Sstevel@tonic-gate 			str->ioDone += str->iovCur->iov_len;
2340Sstevel@tonic-gate 			str->iovCur++;
2350Sstevel@tonic-gate 			str->iovCurCount--;
2360Sstevel@tonic-gate 		}
2370Sstevel@tonic-gate 	}
2380Sstevel@tonic-gate }
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate /* Add a stream to Done list and deselect the FD. */
2410Sstevel@tonic-gate static void
done(evContext opaqueCtx,evStream * str)2420Sstevel@tonic-gate done(evContext opaqueCtx, evStream *str) {
2430Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	if (ctx->strLast != NULL) {
2460Sstevel@tonic-gate 		str->prevDone = ctx->strLast;
2470Sstevel@tonic-gate 		ctx->strLast->nextDone = str;
2480Sstevel@tonic-gate 		ctx->strLast = str;
2490Sstevel@tonic-gate 	} else {
2500Sstevel@tonic-gate 		INSIST(ctx->strDone == NULL);
2510Sstevel@tonic-gate 		ctx->strDone = ctx->strLast = str;
2520Sstevel@tonic-gate 	}
2530Sstevel@tonic-gate 	evDeselectFD(opaqueCtx, str->file);
2540Sstevel@tonic-gate 	str->file.opaque = NULL;
2550Sstevel@tonic-gate 	/* evDrop() will call evCancelRW() on us. */
2560Sstevel@tonic-gate }
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate /* Dribble out some bytes on the stream.  (Called by evDispatch().) */
2590Sstevel@tonic-gate static void
writable(evContext opaqueCtx,void * uap,int fd,int evmask)2600Sstevel@tonic-gate writable(evContext opaqueCtx, void *uap, int fd, int evmask) {
2610Sstevel@tonic-gate 	evStream *str = uap;
2620Sstevel@tonic-gate 	int bytes;
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate 	UNUSED(evmask);
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 	bytes = writev(fd, str->iovCur, str->iovCurCount);
2670Sstevel@tonic-gate 	if (bytes > 0) {
2680Sstevel@tonic-gate 		if ((str->flags & EV_STR_TIMEROK) != 0)
2690Sstevel@tonic-gate 			evTouchIdleTimer(opaqueCtx, str->timer);
2700Sstevel@tonic-gate 		consume(str, bytes);
2710Sstevel@tonic-gate 	} else {
2720Sstevel@tonic-gate 		if (bytes < 0 && errno != EINTR) {
2730Sstevel@tonic-gate 			str->ioDone = -1;
2740Sstevel@tonic-gate 			str->ioErrno = errno;
2750Sstevel@tonic-gate 		}
2760Sstevel@tonic-gate 	}
2770Sstevel@tonic-gate 	if (str->ioDone == -1 || str->ioDone == str->ioTotal)
2780Sstevel@tonic-gate 		done(opaqueCtx, str);
2790Sstevel@tonic-gate }
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate /* Scoop up some bytes from the stream.  (Called by evDispatch().) */
2820Sstevel@tonic-gate static void
readable(evContext opaqueCtx,void * uap,int fd,int evmask)2830Sstevel@tonic-gate readable(evContext opaqueCtx, void *uap, int fd, int evmask) {
2840Sstevel@tonic-gate 	evStream *str = uap;
2850Sstevel@tonic-gate 	int bytes;
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 	UNUSED(evmask);
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate 	bytes = readv(fd, str->iovCur, str->iovCurCount);
2900Sstevel@tonic-gate 	if (bytes > 0) {
2910Sstevel@tonic-gate 		if ((str->flags & EV_STR_TIMEROK) != 0)
2920Sstevel@tonic-gate 			evTouchIdleTimer(opaqueCtx, str->timer);
2930Sstevel@tonic-gate 		consume(str, bytes);
2940Sstevel@tonic-gate 	} else {
2950Sstevel@tonic-gate 		if (bytes == 0)
2960Sstevel@tonic-gate 			str->ioDone = 0;
2970Sstevel@tonic-gate 		else {
2980Sstevel@tonic-gate 			if (errno != EINTR) {
2990Sstevel@tonic-gate 				str->ioDone = -1;
3000Sstevel@tonic-gate 				str->ioErrno = errno;
3010Sstevel@tonic-gate 			}
3020Sstevel@tonic-gate 		}
3030Sstevel@tonic-gate 	}
3040Sstevel@tonic-gate 	if (str->ioDone <= 0 || str->ioDone == str->ioTotal)
3050Sstevel@tonic-gate 		done(opaqueCtx, str);
3060Sstevel@tonic-gate }
307*11038SRao.Shoaib@Sun.COM 
308*11038SRao.Shoaib@Sun.COM /*! \file */
309