Blame src/lib/libast/sfio/sfpoll.c

Packit Service a8c26c
/***********************************************************************
Packit Service a8c26c
*                                                                      *
Packit Service a8c26c
*               This software is part of the ast package               *
Packit Service a8c26c
*          Copyright (c) 1985-2011 AT&T Intellectual Property          *
Packit Service a8c26c
*                      and is licensed under the                       *
Packit Service a8c26c
*                 Eclipse Public License, Version 1.0                  *
Packit Service a8c26c
*                    by AT&T Intellectual Property                     *
Packit Service a8c26c
*                                                                      *
Packit Service a8c26c
*                A copy of the License is available at                 *
Packit Service a8c26c
*          http://www.eclipse.org/org/documents/epl-v10.html           *
Packit Service a8c26c
*         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
Packit Service a8c26c
*                                                                      *
Packit Service a8c26c
*              Information and Software Systems Research               *
Packit Service a8c26c
*                            AT&T Research                             *
Packit Service a8c26c
*                           Florham Park NJ                            *
Packit Service a8c26c
*                                                                      *
Packit Service a8c26c
*                 Glenn Fowler <gsf@research.att.com>                  *
Packit Service a8c26c
*                  David Korn <dgk@research.att.com>                   *
Packit Service a8c26c
*                   Phong Vo <kpv@research.att.com>                    *
Packit Service a8c26c
*                                                                      *
Packit Service a8c26c
***********************************************************************/
Packit Service a8c26c
#include	"sfhdr.h"
Packit Service a8c26c
Packit Service a8c26c
/*	Poll a set of streams to see if any is available for I/O.
Packit Service a8c26c
**	Ready streams are moved to front of array but retain the
Packit Service a8c26c
**	same relative order.
Packit Service a8c26c
**
Packit Service a8c26c
**	Written by Kiem-Phong Vo.
Packit Service a8c26c
*/
Packit Service a8c26c
Packit Service a8c26c
#if __STD_C
Packit Service a8c26c
int sfpoll(Sfio_t** fa, reg int n, int tm)
Packit Service a8c26c
#else
Packit Service a8c26c
int sfpoll(fa, n, tm)
Packit Service a8c26c
Sfio_t**	fa;	/* array of streams to poll		*/
Packit Service a8c26c
reg int		n;	/* number of streams in array		*/
Packit Service a8c26c
int		tm;	/* time in millisecs for select/poll	*/
Packit Service a8c26c
#endif
Packit Service a8c26c
{
Packit Service a8c26c
	reg int		r, c, m, np, eintr;
Packit Service a8c26c
	reg Sfio_t*	f;
Packit Service a8c26c
	reg int		*status, *check;
Packit Service a8c26c
Packit Service a8c26c
	if(n <= 0 || !fa)
Packit Service a8c26c
		return -1;
Packit Service a8c26c
Packit Service a8c26c
	if(!(status = (int*)malloc(2*n*sizeof(int))) )
Packit Service a8c26c
		return -1;
Packit Service a8c26c
	check = status+n; /* streams that need polling */
Packit Service a8c26c
Packit Service a8c26c
	/* a SF_READ stream is ready if there is buffered read data */
Packit Service a8c26c
#define RDREADY(f)	(((f->mode&SF_READ) && f->next < f->endb) || \
Packit Service a8c26c
			 ((f->mode&SF_WRITE) && f->proc && f->proc->ndata > 0) )
Packit Service a8c26c
Packit Service a8c26c
	/* a SF_WRITE stream is ready if there is no write data */
Packit Service a8c26c
#define WRREADY(f)	(!(f->mode&SF_WRITE) || f->next == f->data)
Packit Service a8c26c
Packit Service a8c26c
#define HASAUXFD(f)	(f->proc && f->proc->file >= 0 && f->proc->file != f->file)
Packit Service a8c26c
Packit Service a8c26c
	for(r = c = eintr = 0; r < n; ++r) /* compute streams that must be checked */
Packit Service a8c26c
	{	f = fa[r];
Packit Service a8c26c
		status[r] = 0;
Packit Service a8c26c
Packit Service a8c26c
		/* terminate poll on interrupt? */
Packit Service a8c26c
		if(f->flags&SF_IOINTR)
Packit Service a8c26c
			eintr++;
Packit Service a8c26c
		/* check accessibility */
Packit Service a8c26c
		m = f->mode&SF_RDWR;
Packit Service a8c26c
		if((int)f->mode != m && _sfmode(f,m,0) < 0)
Packit Service a8c26c
			continue;
Packit Service a8c26c
Packit Service a8c26c
		if((f->flags&SF_READ) && RDREADY(f))
Packit Service a8c26c
			status[r] |= SF_READ;
Packit Service a8c26c
Packit Service a8c26c
		if((f->flags&SF_WRITE) && WRREADY(f))
Packit Service a8c26c
			status[r] |= SF_WRITE;
Packit Service a8c26c
Packit Service a8c26c
		if((f->flags&SF_RDWR) == status[r])
Packit Service a8c26c
			continue;
Packit Service a8c26c
Packit Service a8c26c
		/* has discipline, ask its opinion */
Packit Service a8c26c
		if(f->disc && f->disc->exceptf)
Packit Service a8c26c
		{	if((m = (*f->disc->exceptf)(f,SF_DPOLL,&tm,f->disc)) < 0)
Packit Service a8c26c
				continue;
Packit Service a8c26c
			else if(m > 0)
Packit Service a8c26c
			{	status[r] = m&SF_RDWR;
Packit Service a8c26c
				continue;
Packit Service a8c26c
			}
Packit Service a8c26c
		}
Packit Service a8c26c
Packit Service a8c26c
		if(f->extent < 0) /* unseekable stream, must poll/select */
Packit Service a8c26c
			check[c++] = r;
Packit Service a8c26c
		else /* seekable streams are always ready */
Packit Service a8c26c
		{	if(f->flags&SF_READ)
Packit Service a8c26c
				status[r] |= SF_READ;
Packit Service a8c26c
			if(f->flags&SF_WRITE)
Packit Service a8c26c
				status[r] |= SF_WRITE;
Packit Service a8c26c
		}
Packit Service a8c26c
	}
Packit Service a8c26c
	/* terminate poll on interrupt only if all streams marked SF_IOINTR */
Packit Service a8c26c
	eintr = eintr == n ? -1 : EINTR;
Packit Service a8c26c
Packit Service a8c26c
	np = -1;
Packit Service a8c26c
#if _lib_poll
Packit Service a8c26c
	if(c > 0)
Packit Service a8c26c
	{	struct pollfd*	fds;
Packit Service a8c26c
Packit Service a8c26c
		/* construct the poll array */
Packit Service a8c26c
		for(m = 0, r = 0; r < c; ++r, ++m)
Packit Service a8c26c
		{	f = fa[check[r]];
Packit Service a8c26c
			if(HASAUXFD(f))
Packit Service a8c26c
				m += 1;
Packit Service a8c26c
		}
Packit Service a8c26c
		if(!(fds = (struct pollfd*)malloc(m*sizeof(struct pollfd))) )
Packit Service a8c26c
			return -1;
Packit Service a8c26c
Packit Service a8c26c
		for(m = 0, r = 0; r < c; ++r, ++m)
Packit Service a8c26c
		{	f = fa[check[r]];
Packit Service a8c26c
Packit Service a8c26c
			fds[m].fd = f->file;
Packit Service a8c26c
			fds[m].events = fds[m].revents = 0;
Packit Service a8c26c
Packit Service a8c26c
			if((f->flags&SF_WRITE) && !WRREADY(f) )
Packit Service a8c26c
				fds[m].events |= POLLOUT;
Packit Service a8c26c
Packit Service a8c26c
			if((f->flags&SF_READ)  && !RDREADY(f) )
Packit Service a8c26c
			{	/* a sfpopen situation with two file descriptors */
Packit Service a8c26c
				if((f->mode&SF_WRITE) && HASAUXFD(f))
Packit Service a8c26c
				{	m += 1;
Packit Service a8c26c
					fds[m].fd = f->proc->file;
Packit Service a8c26c
					fds[m].revents = 0;
Packit Service a8c26c
				}
Packit Service a8c26c
Packit Service a8c26c
				fds[m].events |= POLLIN;
Packit Service a8c26c
			}
Packit Service a8c26c
		}
Packit Service a8c26c
Packit Service a8c26c
		while((np = SFPOLL(fds,m,tm)) < 0 )
Packit Service a8c26c
		{	if(errno == eintr || errno == EAGAIN)
Packit Service a8c26c
				errno = 0;
Packit Service a8c26c
			else	break;
Packit Service a8c26c
		}
Packit Service a8c26c
		if(np > 0) /* poll succeeded */
Packit Service a8c26c
			np = c;
Packit Service a8c26c
Packit Service a8c26c
		for(m = 0, r = 0; r < np; ++r, ++m)
Packit Service a8c26c
		{	f = fa[check[r]];
Packit Service a8c26c
Packit Service a8c26c
			if((f->flags&SF_WRITE) && !WRREADY(f) )
Packit Service a8c26c
			{	if(fds[m].revents&POLLOUT)
Packit Service a8c26c
					status[check[r]] |= SF_WRITE;
Packit Service a8c26c
			}
Packit Service a8c26c
Packit Service a8c26c
			if((f->flags&SF_READ)  && !RDREADY(f))
Packit Service a8c26c
			{	if((f->mode&SF_WRITE) && HASAUXFD(f))
Packit Service a8c26c
					m += 1;
Packit Service a8c26c
				if(fds[m].revents&POLLIN)
Packit Service a8c26c
					status[check[r]] |= SF_READ;
Packit Service a8c26c
			}
Packit Service a8c26c
		}
Packit Service a8c26c
Packit Service a8c26c
		free((Void_t*)fds);
Packit Service a8c26c
	}
Packit Service a8c26c
#endif /*_lib_poll*/
Packit Service a8c26c
Packit Service a8c26c
#if _lib_select
Packit Service a8c26c
	if(np < 0 && c > 0)
Packit Service a8c26c
	{	fd_set		rd, wr;
Packit Service a8c26c
		struct timeval	tmb, *tmp;
Packit Service a8c26c
Packit Service a8c26c
		FD_ZERO(&rd);
Packit Service a8c26c
		FD_ZERO(&wr);
Packit Service a8c26c
		m = 0;
Packit Service a8c26c
		for(r = 0; r < c; ++r)
Packit Service a8c26c
		{	f = fa[check[r]];
Packit Service a8c26c
Packit Service a8c26c
			if(f->file > m)
Packit Service a8c26c
				m = f->file;
Packit Service a8c26c
Packit Service a8c26c
			if((f->flags&SF_WRITE) && !WRREADY(f))
Packit Service a8c26c
				FD_SET(f->file,&wr);
Packit Service a8c26c
Packit Service a8c26c
			if((f->flags&SF_READ)  && !RDREADY(f))
Packit Service a8c26c
			{	if((f->mode&SF_WRITE) && HASAUXFD(f))
Packit Service a8c26c
				{	if(f->proc->file > m)
Packit Service a8c26c
						m = f->proc->file;
Packit Service a8c26c
					FD_SET(f->proc->file, &rd);
Packit Service a8c26c
				}
Packit Service a8c26c
				else	FD_SET(f->file,&rd);
Packit Service a8c26c
			}
Packit Service a8c26c
		}
Packit Service a8c26c
		if(tm < 0)
Packit Service a8c26c
			tmp = NIL(struct timeval*);
Packit Service a8c26c
		else
Packit Service a8c26c
		{	tmp = &tm;;
Packit Service a8c26c
			tmb.tv_sec = tm/SECOND;
Packit Service a8c26c
			tmb.tv_usec = (tm%SECOND)*SECOND;
Packit Service a8c26c
		}
Packit Service a8c26c
Packit Service a8c26c
		while((np = select(m+1,&rd,&wr,NIL(fd_set*),tmp)) < 0 )
Packit Service a8c26c
		{	if(errno == eintr)
Packit Service a8c26c
				errno = 0;
Packit Service a8c26c
			else	break;
Packit Service a8c26c
		}
Packit Service a8c26c
		if(np > 0)
Packit Service a8c26c
			np = c;
Packit Service a8c26c
Packit Service a8c26c
		for(r = 0; r < np; ++r)
Packit Service a8c26c
		{	f = fa[check[r]];
Packit Service a8c26c
Packit Service a8c26c
			if((f->flags&SF_WRITE) && !WRREADY(f) )
Packit Service a8c26c
			{	if(FD_ISSET(f->file,&wr) )
Packit Service a8c26c
					status[check[r]] |= SF_WRITE;
Packit Service a8c26c
			}
Packit Service a8c26c
Packit Service a8c26c
			if((f->flags&SF_READ) && !RDREADY(f) )
Packit Service a8c26c
			{	if((f->mode&SF_WRITE) && HASAUXFD(f) )
Packit Service a8c26c
				{	if(FD_ISSET(f->proc->file, &rd) )
Packit Service a8c26c
						status[check[r]] |= SF_READ;
Packit Service a8c26c
				}
Packit Service a8c26c
				else
Packit Service a8c26c
				{	if(FD_ISSET(f->file,&rd) )
Packit Service a8c26c
						status[check[r]] |= SF_READ;
Packit Service a8c26c
				}
Packit Service a8c26c
			}
Packit Service a8c26c
		}
Packit Service a8c26c
	}
Packit Service a8c26c
#endif /*_lib_select*/
Packit Service a8c26c
Packit Service a8c26c
	for(r = c = 0; c < n; ++c)
Packit Service a8c26c
	{	if(status[c] == 0)
Packit Service a8c26c
			continue;
Packit Service a8c26c
Packit Service a8c26c
		f = fa[c];
Packit Service a8c26c
		f->val = (ssize_t)status[c];
Packit Service a8c26c
Packit Service a8c26c
		/* announce status */
Packit Service a8c26c
		if(f->disc && f->disc->exceptf)
Packit Service a8c26c
			(*f->disc->exceptf)(f,SF_READY,(Void_t*)(long)status[c],f->disc);
Packit Service a8c26c
Packit Service a8c26c
		if(c > r) /* move to front of list */
Packit Service a8c26c
		{	fa[c] = fa[r];
Packit Service a8c26c
			fa[r] = f;
Packit Service a8c26c
		}
Packit Service a8c26c
		r += 1;
Packit Service a8c26c
	}
Packit Service a8c26c
Packit Service a8c26c
	free((Void_t*)status);
Packit Service a8c26c
	return r ? r : np < 0 ? -1 : 0;
Packit Service a8c26c
}