home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 January
/
usenetsourcesnewsgroupsinfomagicjanuary1994.iso
/
sources
/
misc
/
volume32
/
pol
/
part01
/
pol.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-10-18
|
11KB
|
458 lines
/*
pol.c - poll/select() implemented as a device driver
version 1.04 9/17/92
Bruce Momjian (root%candle.uucp@bts.com)
*/
/* tabs = 4 */
/* Include files */
#ifdef DEBUG
#define DB(x) x
#else
#define DB(x)
#endif
#include <errno.h>
#include <limits.h>
#include <sys/pol.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/dir.h>
#include <sys/signal.h>
#include <sys/user.h>
#include <sys/file.h>
#include <sys/inode.h>
#include <sys/conf.h>
#include <sys/tty.h>
#include <sys/termio.h>
#include <sys/sxt.h>
#include <sys/sysmacros.h>
#define TTIN_FUNCT ttin
#define TTWRITE_FUNCT ttwrite
#define POL_READ_FLAG 0
#define POL_WRITE_FLAG 1
#define IS_PTM 1
#define IS_PIPE 4
#define TBUF_CNT_OFF (int)&(((struct tty *)0)->t_tbuf.c_count)
#define TOUTQ_CC_OFF (int)&(((struct tty *)0)->t_outq.c_cc)
#define TCANQ_CC_OFF (int)&(((struct tty *)0)->t_canq.c_cc)
#define TRAWQ_CC_OFF (int)&(((struct tty *)0)->t_rawq.c_cc)
#define T_CFLAG_OFF (int)&(((struct tty *)0)->t_cflag)
#define T_STATE_OFF (int)&(((struct tty *)0)->t_state)
int pol_in_use = 0; /* is pol opened, also sleep addr. */
int pol_intr = 0; /* was pol interupted during scan */
/* pty and sxt external symbols */
extern struct tty sxt_tty[], pts_tty[];
extern int sxtopen(), ptmopen();
extern char sxt_buf[];
/* kernel symbols */
extern int ttin(), ttwrite();
/* my function symbols */
int ttinpol(), ttwrpol(), poltimeo();
extern time_t lbolt; /* ticks since boot */
struct pol_table {
caddr_t addr; /* usually struct tty pointer */
short fd;
short ttyflags;
};
/*---------------------------------------------------------------------------
**
** polopen - called for each open() call
**
**--------------------------------------------------------------------------*/
polopen(fdev, flags)
int fdev, flags;
{
if (pol_in_use == 0)
{
if (linesw[0].l_input != TTIN_FUNCT) /* is linesw[] ok? */
{
printf("pol error: linesw structure corrupted.\n");
u.u_error = ENOMSG;
u.u_rval1 = -1;
return -1;
}
if (linesw[0].l_write != TTWRITE_FUNCT)
{
printf("pol error: linesw structure corrupted.\n");
u.u_error = ENOMSG;
u.u_rval1 = -1;
return -1;
}
spltty(); /* don't let anyone use them yet */
linesw[0].l_input = ttinpol;/* substitute our own functions */
linesw[0].l_write = ttwrpol;
spl0();
pol_in_use = 1; /* mark pol in use */
}
return 0;
}
/*---------------------------------------------------------------------------
**
** polclose - called only for last close() call
**
**--------------------------------------------------------------------------*/
polclose(fdev)
int fdev;
{
pol_in_use = 0;
if (linesw[0].l_input != ttinpol) /* is linesw[] ok? */
{
printf("pol error: linesw structure corrupted.\n");
u.u_error = ENOMSG;
u.u_rval1 = -1;
}
else if (linesw[0].l_write != ttwrpol)
{
printf("pol error: linesw structure corrupted.\n");
u.u_error = ENOMSG;
u.u_rval1 = -1;
}
else u.u_rval1 = 0;
spltty(); /* don't let anyone use them */
linesw[0].l_input = ttin; /* replace the originals */
linesw[0].l_write = ttwrite;
spl0();
return u.u_rval1;
}
/*---------------------------------------------------------------------------
**
** polioctl - called for each ioctl() call
**
**--------------------------------------------------------------------------*/
polioctl(fdev, command, polfd_p, mode)
int fdev, command, mode;
struct polfd *polfd_p;
{
int i,
rfds_num = 0,
wfds_num = 0,
hits = 0,
char_cnt,
timeout_idx = 0;
time_t start_ticks = lbolt,
timeout_ticks;
struct polfd pol_s;
struct pol_table rfds_pol[NPOLFILE],
wfds_pol[NPOLFILE];
DB(printf("Start func\n"));
if (copyin(polfd_p, &pol_s, sizeof(struct polfd)) != 0)
{
u.u_error = EFAULT;
u.u_rval1 = -1;
return -1;
}
if (command != POL_FDS) /* illegal ioctl() request */
{
u.u_error = EINVAL;
u.u_rval1 = -1;
return -1;
}
if (pol_s.timeout != -1 && pol_s.timeout != 0) /* is there a timeout? */
{
timeout_ticks = start_ticks + pol_s.timeout * (HZ)/1000;
timeout_idx = timeout( poltimeo, /* wake us up later */
(caddr_t)NULL,
pol_s.timeout * (HZ)/1000);
}
DB(printf("Start for loop.\n"));
DB(printf("Start while loop.\n"));
/* COLLECT READ AND WRITE ADDRESSES TO SCAN */
if (poladdr( pol_s.rfds, rfds_pol, &rfds_num, POL_READ_FLAG) == -1)
{
if (timeout_idx != 0 && lbolt < timeout_ticks)
untimeout(timeout_idx);
return -1;
}
if (poladdr( pol_s.wfds, wfds_pol, &wfds_num, POL_WRITE_FLAG) == -1)
{
if (timeout_idx != 0 && lbolt < timeout_ticks)
untimeout(timeout_idx);
return -1;
}
pol_s.rfds = pol_s.wfds = 0;
/* MAIN POLLING LOOP */
while(1)
{
do
{
pol_intr = 0;
spl0();
/* READS */
for (i=0; i < rfds_num; i++)
{
if (rfds_pol[i].ttyflags != IS_PIPE &&
!(*(short *)(rfds_pol[i].addr + T_CFLAG_OFF) & CLOCAL) &&
!(*(short *)(rfds_pol[i].addr + T_STATE_OFF) & CARR_ON))
char_cnt = 1;
else
switch (rfds_pol[i].ttyflags)
{
case IS_PTM : char_cnt =
*(int *)(rfds_pol[i].addr + TOUTQ_CC_OFF) +
*(short *)(rfds_pol[i].addr + TBUF_CNT_OFF);
break;
case IS_PIPE : char_cnt = *(int *)(rfds_pol[i].addr);
break;
default :
char_cnt =
*(int *)(rfds_pol[i].addr + TCANQ_CC_OFF);
if ((((struct tty *)rfds_pol->addr)->t_lflag
& ICANON) == 0)
char_cnt +=
*(int *)(rfds_pol[i].addr + TRAWQ_CC_OFF);
break;
}
if (char_cnt != 0)
{
pol_s.rfds |= (1 << rfds_pol[i].fd);
hits++;
}
}
/* WRITES */
for (i=0; i < wfds_num; i++)
{
char_cnt = 0;
if (wfds_pol[i].ttyflags != IS_PIPE &&
!(*(short *)(wfds_pol[i].addr + T_CFLAG_OFF) & CLOCAL) &&
!(*(short *)(wfds_pol[i].addr + T_STATE_OFF) & CARR_ON))
char_cnt = 1;
else
switch (wfds_pol[i].ttyflags)
{
case IS_PIPE :
if (*(int *)(wfds_pol[i].addr) < PIPE_MAX)
char_cnt = 1;
default :
if (!(*(short *)(wfds_pol[i].addr + T_STATE_OFF)
& TBLOCK))
char_cnt = 1;
}
if (char_cnt != 0)
{
pol_s.wfds |= (1 << wfds_pol[i].fd);
hits++;
}
}
/* DO WE HAVE SOMETHING TO REPORT? */
if (hits != 0)
{
if (timeout_idx != 0 && lbolt < timeout_ticks)
untimeout(timeout_idx);
DB(printf("got result\n"));
if (copyout(&pol_s, polfd_p, sizeof(struct polfd)) != 0)
{
u.u_error = EFAULT;
u.u_rval1 = -1;
}
else u.u_rval1 = hits;
return u.u_rval1;
}
spltty();
} while (pol_intr != 0); /* was there activity during scan */
/* GO TO SLEEP */
DB(printf("Going to sleep\n"));
if (pol_s.timeout == 0 || (
pol_s.timeout != -1 && lbolt >= timeout_ticks))
{
spl0();
if (timeout_idx != 0 && lbolt < timeout_ticks)
untimeout(timeout_idx);
u.u_rval1 = 0;
return 0;
}
sleep((caddr_t *)&pol_in_use, PSLEP);
spl0();
}
}
/*---------------------------------------------------------------------------
**
** wakepl - this is our wakeup substitute
**
**--------------------------------------------------------------------------*/
wakepl(caddr)
caddr_t caddr;
{
if (pol_in_use > 0)
{
DB(printf("wakepl called\n"));
wakeup((caddr_t)&pol_in_use);
}
return wakeup(caddr); /* call original wakeup() */
}
/*---------------------------------------------------------------------------
**
** poltimeo - this is our timeout() wakeup so we can return on timeout
**
**--------------------------------------------------------------------------*/
poltimeo()
{
if (pol_in_use > 0)
{
DB(printf("timedout wakeup\n"));
wakeup((caddr_t)&pol_in_use); /* wake up all pol's */
}
}
/*---------------------------------------------------------------------------
**
** ttinpol - out ttin() substitute
**
**--------------------------------------------------------------------------*/
ttinpol(tty_p, flag)
struct tty *tty_p;
int flag;
{
if (pol_in_use > 0)
{
DB(printf("ttinpol called\n"));
wakeup((caddr_t)&pol_in_use);
}
pol_intr = 1;
return ttin(tty_p, flag); /* call original ttin() */
}
/*---------------------------------------------------------------------------
**
** ttwrpol - out ttwrite() substitute
**
**--------------------------------------------------------------------------*/
ttwrpol(tty_p)
struct tty *tty_p;
{
if (pol_in_use > 0)
{
DB(printf("ttwrpol called\n"));
wakeup((caddr_t)&pol_in_use);
}
pol_intr = 1;
return ttwrite(tty_p); /* call original ttwrite() */
}
/*---------------------------------------------------------------------------
**
** poladdr - collects addresses to scan after each char in or out
**
**--------------------------------------------------------------------------*/
poladdr(fmask, fds_pol, num_fds, flag)
int fmask, *num_fds, flag;
struct pol_table *fds_pol;
{
int i, j;
struct inode *fd_inode;
struct tty *major_tty;
struct Link *fd_link;
for (i = 0; i != -1 && i <= NPOLFILE; i++) /* for each fd */
{
if ( (fmask & (1 << i)) == 0) /* is it marked? */
continue;
DB(printf("Found fd\n"));
fds_pol->fd = i;
fds_pol->ttyflags = 0;
if (u.u_ofile[i] == NULL) /* is it active? */
{
u.u_error = EBADF;
u.u_rval1 = -1;
return -1;
}
fd_inode = (u.u_ofile[i])->f_up.f_uinode; /*is it active? */
if (fd_inode == NULL)
{
u.u_error = EBADF;
u.u_rval1 = -1;
return -1;
}
/* IS IT A CHARACTER SPECIAL DEVICE? */
if ( (fd_inode->i_ftype & IFMT) == IFCHR)
{
DB(printf("char device\n"));
DB(printf("major %d\n",major(fd_inode->i_rdev)));
DB(printf("minor %d\n",minor(fd_inode->i_rdev)));
/* DOES THIS MAJOR NUMBER LACK A TTY STRUCTURE? */
if ( (major_tty=cdevsw[major(fd_inode->i_rdev)].d_ttys) == 0)
/* IS IT AN SXT DEVICE */
if (cdevsw[major(fd_inode->i_rdev)].d_open == sxtopen)
fds_pol->addr = (char *)sxt_buf +
(long)LINK(minor(fd_inode->i_rdev)) *
(long)(sizeof(struct Link) +
sizeof(struct Channel) * (MAXPCHAN-1)) +
(long)&((struct Link *)0)->chans[0] +
CHAN(minor(fd_inode->i_rdev)) *
sizeof(struct Channel) +
(long)&((struct Channel *)0)->tty;
/* IS IT A MASTER PTY DEVICE? */
else if (cdevsw[major(fd_inode->i_rdev)].d_open == ptmopen)
{ /* master ptys */
fds_pol->addr = (char *)pts_tty +
minor(fd_inode->i_rdev) * sizeof(struct tty);
fds_pol->ttyflags = IS_PTM;
}
else
{
u.u_error = ENXIO;
u.u_rval1 = -1;
return -1;
}
else /* it has a tty structure */
fds_pol->addr = (char *)major_tty +
minor(fd_inode->i_rdev) * sizeof(struct tty);
}
else if ( (fd_inode->i_ftype & IFMT) == IFIFO) /* is it a pipe? */
{
fds_pol->addr = (char *)&fd_inode->i_size;
fds_pol->ttyflags = IS_PIPE;
}
else
{
u.u_error = EBADF;
u.u_rval1 = -1;
return -1;
}
DB(printf("Got address\n"));
(*num_fds)++;
fds_pol++;
if ( (fmask &= ~(1 <<i)) == 0) /* remove bit from mask */
break;
}
return 0;
}