From: root@candle.uucp (Bruce Momjian)
Subject: select()/poll() source code posting
Organization: a consultant's basement
Date: Thu, 27 Aug 1992 21:22:35 GMT
X-Newsreader: Tin 1.1 PL5

Attached is a shar file containing an implementation of poll() and
select() for systems that lack them.  It is implemented as a device
driver.  I have called it pol() and selec() so as not to confuse them
with the originals.  It only works on reads and writes.

This package is not ready for prime-time.  If there is enough interest,
and if someone can help me with the intricacies of the tty structure
under different modes, I would be glad to polish it up.

The shar file is 17k.  My thanks to those people in comp.unix.internals
who helped me with some of the details.  This code was written by
looking at other PD device driver implementaions, like fas(async),
pty(ptys), herc(hercules graphics), and mouse(mouse).  The code was
developed on AT&T 386 Unix SVr3.1, which has poll(), but only for
streams. 

-------------------------------------------------------------------
#!/bin/sh
# This is a shell archive (shar 3.32)
# made 08/27/1992 20:44 UTC by root@candle
# Source directory /u/src/pol/tmp
#
# existing files WILL be overwritten
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#    877 -rw-r--r-- INSTALL
#    964 -rw-r--r-- README
#   8399 -rw-r--r-- pol.c
#    521 -rw-r--r-- pol.h
#   2624 -rw-r--r-- pol.lib.c
#    305 -rw-r--r-- poltest.c
#     62 -rw-r--r-- selec.h
#
if touch 2>&1 | fgrep 'amc' > /dev/null
 then TOUCH=touch
 else TOUCH=true
fi
# ============= INSTALL ==============
echo "x - extracting INSTALL (Text)"
sed 's/^X//' << 'SHAR_EOF' > INSTALL &&
XBasically, pol.c is installed as a device driver with this line in 
Xthe mdevice file:
X
Xpol	oci	iHc	pol	0	12	1	1	-1
X					^
X					| major number of your choice
X
XAdd an appropriate file in sdevice.d link this:
X
Xpol	Y	1	0	0	0	0	0	0	0
X
Xand add a file in node.d so a character device called /dev/pol getsc
Xcreated:
X
Xpol	pol	c	0
X
XOnly one entry is needed, even though many programs can pol at the same
Xtime. 
X
XAdd a subdirectory under /etc/conf/pack.d called pol and compile pol.c
Xand copy it into /etc/conf/pack.d/pol/Driver.o.
X
XCompile pol.lib.c and install it in your personal C library.  It will be
Xthe link points for pol() and selec().
X
XInstall pol.h and selec.h in /usr/include/sys.
X
XREADME 		- this file
Xpol.c		- device driver
Xpol.lib.c	- C library module
Xpol.h		- /usr/include/sys/pol.h file
Xselec.h		- /usr/include/sys/selec.h file
Xpoltest.c	- used to test the device driver
SHAR_EOF
$TOUCH -am 0827161092 INSTALL &&
chmod 0644 INSTALL ||
echo "restore of INSTALL failed"
set `wc -c INSTALL`;Wc_c=$1
if test "$Wc_c" != "877"; then
	echo original size 877, current size $Wc_c
fi
# ============= README ==============
echo "x - extracting README (Text)"
sed 's/^X//' << 'SHAR_EOF' > README &&
XBasically, this package implements poll() and select() as a device
Xdriver.  It is called pol() and selec() so as not to be confused with
Xthe real thing.
X
XThe driver accepts bit masks of read and write file descriptors.  It
Xfollows the descriptors to the file, then inode tables and gets the
Xmajor and minor device numbers.  It then finds the tty structures
Xassociated with those devices and stores their addresses.
X
XIt scans through the addresses once, looking for read or written
Xcharacters, then either returns or goes to sleep.  Upon invocation, it
Xreplaces the standard tty input/output functions with its own functions,
Xwhich wake up the driver and call the usual tty functions.  In this way,
Xthe driver is woken up when tty activity occurs. 
X
XA C library library is provided to translate the normal poll() and
Xselect() parameters into pol device driver parameters, and then call the
Xdevice driver.
X
XBruce Momjian, root@candle.uucp (root%candle.uucp@bts.com)
SHAR_EOF
$TOUCH -am 0827153792 README &&
chmod 0644 README ||
echo "restore of README failed"
set `wc -c README`;Wc_c=$1
if test "$Wc_c" != "964"; then
	echo original size 964, current size $Wc_c
fi
# ============= pol.c ==============
echo "x - extracting pol.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > pol.c &&
X/*
X	pol.c	- poll/select() implemented as a device driver
X
X	Bruce Momjian (root%candle.uucp@bts.com
X
X*/
X
X/* tabs = 4 */
X/* Include files */
X#undef DEBUG
X#undef USE_BUF	/* use tty->t/rbuf */
X
X#ifdef DEBUG
X#define	DB(x)	x
X#else
X#define DB(x)
X#endif
X
X#include <errno.h>
X#include <sys/pol.h>
X#include <sys/types.h>
X#include <sys/param.h>
X#include <sys/ioctl.h>
X#include <sys/dir.h>
X#include <sys/signal.h>
X#include <sys/user.h>
X#include <sys/file.h>
X#include <sys/inode.h>
X#include <sys/conf.h>
X#include <sys/tty.h>
X#include <sys/sxt.h>
X#include <sys/sysmacros.h>
X
X#define TTIN_FUNCT		ttin
X#define TTWRITE_FUNCT	ttwrite
X#define POL_READ_FLAG		0
X#define POL_WRITE_FLAG		1
X
Xint	pol_uses = 0;
Xint pol_intr = 0;
X
Xextern struct tty sxt_tty[], pts_tty[];
Xextern int sxtopen(), ptmopen();
Xextern char sxt_buf[];
Xextern int ttin(), ttwrite();
X
Xint ttinpol(), ttwrpol(), poltimeo();
Xextern time_t lbolt;
X
Xstruct pol_table {
X		caddr_t addr
X#ifdef USE_BUF
X				, addr2
X#endif
X		;
X		int		fd;
X};
X
X/*---------------------------------------------------------------------------
X**
X**	polopen
X**
X**--------------------------------------------------------------------------*/
Xpolopen(fdev, flags)
Xint	fdev, flags;
X{
X	if (pol_uses == 0)
X	{
X		if (linesw[0].l_input != TTIN_FUNCT)
X		{
X			printf("pol error:  linesw structure corrupted.\n");
X		  	u.u_error = ENOMSG;
X  			u.u_rval1 = -1;
X			return -1;
X		}
X		if (linesw[0].l_write != TTWRITE_FUNCT)
X		{
X			printf("pol error:  linesw structure corrupted.\n");
X			u.u_error = ENOMSG;
X			u.u_rval1 = -1;
X			return -1;
X		}
X		spltty();
X		linesw[0].l_input = ttinpol;
X		linesw[0].l_write = ttwrpol;
X		spl0();
X		pol_uses = 1;
X	}		
X	return 0;
X}
X
X/*---------------------------------------------------------------------------
X**
X**	polclose
X**
X**--------------------------------------------------------------------------*/
Xpolclose(fdev)
Xint	fdev;
X{
X	pol_uses = 0;
X	if (linesw[0].l_input != ttinpol)
X	{
X		printf("pol error:  linesw structure corrupted.\n");
X		u.u_error = ENOMSG;
X		u.u_rval1 = -1;
X	}
X	else if (linesw[0].l_write != ttwrpol)
X	{
X		printf("pol error:  linesw structure corrupted.\n");
X		u.u_error = ENOMSG;
X		u.u_rval1 = -1;
X	}
X	else	u.u_rval1 = 0;
X	spltty();
X	linesw[0].l_input = ttin;
X	linesw[0].l_write = ttwrite;
X	spl0();
X	return u.u_rval1;
X}
X
X/*---------------------------------------------------------------------------
X**
X**	polioctl
X**
X**--------------------------------------------------------------------------*/
Xpolioctl(fdev, command, polfd_p, mode) 
Xint	fdev, command, mode;
Xstruct polfd *polfd_p;
X{
X	int 	i,
X			rfds_num = 0,
X			wfds_num = 0,
X			hits = 0,
X			timeout_idx = 0;
X	time_t	start_ticks = lbolt, timeout_ticks;
X	struct polfd pol_s;
X	struct pol_table rfds_pol[NPOLFILE],
X					 wfds_pol[NPOLFILE];
X	
X	DB(printf("Start func\n"));
X	if (copyin(polfd_p, &pol_s, sizeof(struct polfd)) != 0)
X	{
X		u.u_error = EFAULT;
X		u.u_rval1 = -1;
X		return -1;
X	}
X	if (command != POL_FDS)
X	{
X		u.u_error = EINVAL;		
X		u.u_rval1 = -1;
X		return -1;
X	}
X	
X	if (pol_s.timeout != -1 && pol_s.timeout != 0)
X	{
X		timeout_ticks = start_ticks + pol_s.timeout * (HZ)/1000;
X		timeout_idx = timeout(	poltimeo,
X								(caddr_t)NULL,
X								pol_s.timeout * (HZ)/1000);
X	}
X
X	DB(printf("Start for loop.\n"));	
X	DB(printf("Start while loop.\n"));
X	if (poladdr( pol_s.rfds, rfds_pol, &rfds_num, POL_READ_FLAG) == -1)
X	{
X		if (timeout_idx != 0 && lbolt < timeout_ticks)
X			untimeout(timeout_idx);
X		return -1;
X	}
X	if (poladdr( pol_s.wfds, wfds_pol, &wfds_num, POL_WRITE_FLAG) == -1)
X	{
X		if (timeout_idx != 0 && lbolt < timeout_ticks)
X			untimeout(timeout_idx);
X		return -1;
X	}
X
X	pol_s.rfds = pol_s.wfds = 0;
X	
X	while(1)
X	{
X		do
X		{
X			pol_intr = 0;
X			spl0();
X			for (i=0; i < rfds_num; i++)
X				if (*(rfds_pol[i].addr) != 0)
X				{
X					pol_s.rfds |= 1 << rfds_pol[i].fd;
X					hits++;
X				}
X#ifdef USE_BUF
X				else if (*(rfds_pol[i].addr2) != 0)
X				{
X					pol_s.rfds |= 1 << rfds_pol[i].fd;
X					hits++;
X				}
X#endif
X			for (i=0; i < wfds_num; i++)
X				if (*(wfds_pol[i].addr) != 0)
X				{
X					pol_s.wfds |= 1 << wfds_pol[i].fd;
X					hits++;
X				}
X#ifdef USE_BUF
X				else if (*(wfds_pol[i].addr2) != 0)
X				{
X					pol_s.wfds |= 1 << wfds_pol[i].fd;
X					hits++;
X				}
X#endif
X			if (hits != 0)
X			{
X				if (timeout_idx != 0 && lbolt < timeout_ticks)
X					untimeout(timeout_idx);
X				DB(printf("got result\n"));
X				if (copyout(&pol_s, polfd_p, sizeof(struct polfd)) != 0)
X				{
X					u.u_error = EFAULT;
X					u.u_rval1 = -1;
X				}
X				else u.u_rval1 = hits;
X				return u.u_rval1;
X			}
X			spltty();
X		} while (pol_intr != 0);
X		DB(printf("Going to sleep\n"));
X		if (pol_s.timeout == 0 || (
X			pol_s.timeout != -1 && lbolt >= timeout_ticks))
X		{
X				spl0();
X				if (timeout_idx != 0 && lbolt < timeout_ticks)
X					untimeout(timeout_idx);
X				u.u_rval1 = 0;
X				return 0;
X		}
X		sleep((caddr_t *)&pol_uses, PSLEP);
X		spl0();
X	}
X}
X
X/*---------------------------------------------------------------------------
X**
X**	wakepl
X**
X**--------------------------------------------------------------------------*/
Xwakepl(caddr)
Xcaddr_t caddr;
X{
X	if (pol_uses > 0)
X	{
X		DB(printf("wakepl called\n"));
X		wakeup((caddr_t)&pol_uses);
X	}
X	return wakeup(caddr);
X}
X
X/*---------------------------------------------------------------------------
X**
X**	poltimeo
X**
X**--------------------------------------------------------------------------*/
Xpoltimeo()
X{
X	if (pol_uses > 0)
X	{
X		DB(printf("timedout wakeup\n"));
X		wakeup((caddr_t)&pol_uses);
X	}
X}
X	
X/*---------------------------------------------------------------------------
X**
X**	ttinpol
X**
X**--------------------------------------------------------------------------*/
Xttinpol(tty_p, flag)
Xstruct tty *tty_p;
Xint flag;
X{
X	if (pol_uses > 0)
X	{
X		DB(printf("ttinpol called\n"));
X		wakeup((caddr_t)&pol_uses);
X	}
X	pol_intr = 1;
X	return ttin(tty_p, flag);
X}
X
X/*---------------------------------------------------------------------------
X**
X**	ttwrpol
X**
X**--------------------------------------------------------------------------*/
Xttwrpol(tty_p)
Xstruct tty *tty_p;
X{
X	if (pol_uses > 0)
X	{
X		DB(printf("ttwrpol called\n"));
X		wakeup((caddr_t)&pol_uses);
X	}
X	pol_intr = 1;
X	return ttwrite(tty_p);
X}
X
X
X/*---------------------------------------------------------------------------
X**
X**	poladdr
X**
X**--------------------------------------------------------------------------*/
Xpoladdr(fmask, fds_pol, num_fds, flag)
Xint fmask, *num_fds, flag;
Xstruct pol_table *fds_pol;
X{
X	int i, j;
X	struct inode *fd_inode;
X	struct tty *major_tty;
X	struct Link *fd_link;
X	
X	for (i = 0; i != -1 && i <= NPOLFILE; i++)
X	{
X		if ( (fmask & (1 << i)) == 0)
X			continue;
X		DB(printf("Found fd\n"));
X		fds_pol->fd = i;
X 		fd_inode = (u.u_ofile[i])->f_up.f_uinode;
X		if ( (fd_inode->i_ftype & IFMT) == IFCHR)
X		{
X			DB(printf("char device\n"));
X			DB(printf("major %d\n",major(fd_inode->i_rdev)));
X			DB(printf("minor %d\n",minor(fd_inode->i_rdev)));
X			if ( (major_tty=cdevsw[major(fd_inode->i_rdev)].d_ttys) == 0)
X				if (cdevsw[major(fd_inode->i_rdev)].d_open == sxtopen)
X				{ /* sxt */
X					fds_pol->addr = (caddr_t)sxt_buf +
X							(long)LINK(minor(fd_inode->i_rdev)) *
X							(long)(sizeof(struct Link) +
X							 sizeof(struct Channel) * (MAXPCHAN-1)) +
X							(long)&((struct Link *)0)->chans[0] +
X							    CHAN(minor(fd_inode->i_rdev)) *
X								sizeof(struct Channel) +
X								(long)&((struct Channel *)0)->tty;
X				}
X				else if (cdevsw[major(fd_inode->i_rdev)].d_open == ptmopen)
X				{			/* master ptys */
X						fds_pol->addr = (caddr_t)pts_tty;
X						flag = !flag;				/* swap reads and writes*/
X				}					
X				else
X				{
X					u.u_error = ENXIO;		
X					u.u_rval1 = -1;
X					return -1;
X				}
X			else
X				fds_pol->addr =
X					(caddr_t)major_tty +
X					minor(fd_inode->i_rdev) * sizeof(struct tty);
X		}
X		else if ( (fd_inode->i_ftype & IFMT) == IFIFO)
X					fds_pol->addr = (caddr_t)&fd_inode->i_size;
X		else
X		{
X			u.u_error = EBADF;		
X			u.u_rval1 = -1;
X			return -1;
X		}
X		DB(printf("Got address\n"));
X		if ( flag == POL_READ_FLAG)
X		{
X#ifdef USE_BUF
X			fds_pol->addr2 = fds_pol->addr +
X							(long)&((struct tty *)0)->t_rbuf.c_count;
X#endif
X			fds_pol->addr += (long)&((struct tty *)0)->t_rawq.c_cc;
X		}
X		else
X		{
X#ifdef USE_BUF
X			fds_pol->addr2 = fds_pol->addr +
X							(long)&((struct tty *)0)->t_tbuf.c_count;
X#endif
X			fds_pol->addr += (long)&((struct tty *)0)->t_outq.c_cc;
X		}
X		(*num_fds)++;
X		fds_pol++;
X		if ( (fmask &= ~(1 <<i)) == 0)
X			break;
X	}
X	return 0;
X}
SHAR_EOF
$TOUCH -am 0827154392 pol.c &&
chmod 0644 pol.c ||
echo "restore of pol.c failed"
set `wc -c pol.c`;Wc_c=$1
if test "$Wc_c" != "8399"; then
	echo original size 8399, current size $Wc_c
fi
# ============= pol.h ==============
echo "x - extracting pol.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > pol.h &&
X/* sys/pol.h */
X
X#define POL_FDS	0x1234dcba
X
Xstruct polfd {
X	int rfds, wfds;				/* file desc to poll */
X	int timeout;			/* events of interest on fd */
X};
X
X#define NPOLFILE	20
X
X/*#define DONT_HAVE_POLL  /* uncomment this out if you don't have poll.h */
X
X#ifdef DONT_HAVE_POLL
X/*
X * Structure of file descriptor/event pairs supplied in
X * the poll arrays.
X */
Xstruct pollfd {
X	int fd;					/* file desc to poll */
X	short events;			/* events of interest on fd */
X	short revents;			/* events that occurred on fd */
X};
X#endif
X
SHAR_EOF
$TOUCH -am 0827163292 pol.h &&
chmod 0644 pol.h ||
echo "restore of pol.h failed"
set `wc -c pol.h`;Wc_c=$1
if test "$Wc_c" != "521"; then
	echo original size 521, current size $Wc_c
fi
# ============= pol.lib.c ==============
echo "x - extracting pol.lib.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > pol.lib.c &&
X/*
X	pol.c	- poll/select() C interface
X
X	Bruce Momjian (root%candle.uucp@bts.com
X
X*/
X
X/* tabs = 4 */
X/* Include files */
X#include <fcntl.h>
X
X#include <sys/pol.h>
X#include <sys/selec.h>
X#include <poll.h>
X
Xstatic int pol_fd = -1;
X
X
X/*---------------------------------------------------------------------------
X**
X**	pol()
X**
X**--------------------------------------------------------------------------*/
Xpol(fds, nfds, timeout)
Xstruct pollfd *fds;
Xunsigned long nfds;
Xint timeout;
X{
X	struct polfd	pl;
X	int i, ret;
X	
X	if ( pol_fd == -1 && (pol_fd=open("/dev/pol",O_RDONLY)) == -1)
X		return -1;
X
X	pl.rfds = pl.wfds = 0;
X	pl.timeout = timeout;
X
X	for (i = 0; i < nfds; i++)
X	{
X		if ((fds[i].events & POLLIN) != 0)
X			pl.rfds |= (1 << fds[i].fd);
X		if ((fds[i].events & POLLOUT) != 0)
X			pl.wfds |= (1 << fds[i].fd);
X	}
X	
X	if ((ret=ioctl(pol_fd, POL_FDS, &pl)) == -1)
X 		return -1;
X
X	if (ret == 0 || ret == -1)
X		pl.rfds = pl.wfds = 0;
X	
X	for (i=0; i < nfds; i++)
X	{
X		fds[i].revents = 0;
X		if ( (pl.rfds & (1 << fds[i].fd)) != 0)
X			fds[i].revents |= POLLIN;
X		if ( (pl.wfds & (1 << fds[i].fd)) != 0)
X			fds[i].revents |= POLLOUT;
X	}
X	return ret;
X}
X	
X/*---------------------------------------------------------------------------
X**
X**	selec()
X**
X**--------------------------------------------------------------------------*/
Xselec(nfds, rfds, wfds, expfds, timeout)
Xunsigned long nfds, *rfds, *wfds, *expfds; /* exceptions not implemented */
Xstruct timeval *timeout;
X{
X	struct polfd	pl;
X	int i, ret;
X	
X	if ( pol_fd == -1 && (pol_fd=open("/dev/pol",O_RDONLY)) == -1)
X		return -1;
X
X	pl.rfds = pl.wfds = 0;
X	if (timeout == 0L)
X		pl.timeout = -1;
X	else
X		pl.timeout = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
X
X	for (i = 0; i < nfds; i++)
X	{
X		if ( (*rfds & (1 << i)) != 0)
X			pl.rfds |= 1 << i;
X		if ( (*wfds & (1 << i)) != 0)
X			pl.wfds |= 1 << i;
X	}
X	
X	if ((ret=ioctl(pol_fd, POL_FDS, &pl)) == -1)
X 		return -1;
X
X	if (ret == 0 || ret == -1)
X		pl.rfds = pl.wfds = 0;
X	*rfds = *wfds = *expfds = 0;
X
X	for (i=0; i < nfds; i++)
X	{
X		if ( (pl.rfds & (1 << i)) != 0)
X			(*rfds) |= (1 << i);
X		if ( (pl.wfds & (1 << i)) != 0)
X			(*wfds) |= (1 << i);
X	}
X	return ret;
X}
X	
X/*---------------------------------------------------------------------------
X**
X**	polclose()
X**
X**--------------------------------------------------------------------------*/
Xpolclose()
X{
X	if (pol_fd != -1)
X		return close(pol_fd);
X	return 0;
X}
X/*---------------------------------------------------------------------------
X**
X**	selecclose()
X**
X**--------------------------------------------------------------------------*/
Xselecclose()
X{
X	return polclose();
X}
SHAR_EOF
$TOUCH -am 0827154392 pol.lib.c &&
chmod 0644 pol.lib.c ||
echo "restore of pol.lib.c failed"
set `wc -c pol.lib.c`;Wc_c=$1
if test "$Wc_c" != "2624"; then
	echo original size 2624, current size $Wc_c
fi
# ============= poltest.c ==============
echo "x - extracting poltest.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > poltest.c &&
X#include <stdio.h>
X#include <fcntl.h>
X#include <poll.h>
X
Xmain()
X{
X	int fd;
X	struct pollfd pl;
X	int x;
X	
X
X	printf("fd = %d\n",fd);
X	pl.fd = 0;
X	pl.events = POLLIN;
X	printf("Begin ioctl, return\n");
X	if ((x=pol(&pl, 1, 5000)) == -1)
X 		halt("PERROR : ioctl fail\n");
X	printf("End ioctl\n");
X	close(fd);
X} 	
SHAR_EOF
$TOUCH -am 0827160292 poltest.c &&
chmod 0644 poltest.c ||
echo "restore of poltest.c failed"
set `wc -c poltest.c`;Wc_c=$1
if test "$Wc_c" != "305"; then
	echo original size 305, current size $Wc_c
fi
# ============= selec.h ==============
echo "x - extracting selec.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > selec.h &&
X/* sys/selec.h */
Xstruct timeval {
X		long tv_usec, tv_sec;
X};
SHAR_EOF
$TOUCH -am 0827152292 selec.h &&
chmod 0644 selec.h ||
echo "restore of selec.h failed"
set `wc -c selec.h`;Wc_c=$1
if test "$Wc_c" != "62"; then
	echo original size 62, current size $Wc_c
fi
exit 0





-- 
Bruce Momjian                      |  830 Blythe Avenue
root%candle.uucp@bts.com           |  Drexel Hill, Pennsylvania 19026 
                                   |  (215) 353-9879(w)  853-3000(h)

-- 
Bruce Momjian                      |  830 Blythe Avenue
root%candle.uucp@bts.com           |  Drexel Hill, Pennsylvania 19026 
                                   |  (215) 353-9879(w)  853-3000(h)