BBN-V6/telnet/ioctrl.c
#
/*
* IO control routines -- enter, delete, and run IO handlers
*/
/* Max number of simultaneous open files in a process */
#define NOFILE 40
/* Max number of fd-driven jobs */
#define MAXJOBS 16
/* Max number of other jobs */
#define MAXOTHERS 10
#define EINTR 4 /* Bad - luck error */
#define EBADDEV 62 /* Await not implemented */
/*
* The job array is indexed by file descriptor.
* A value of 0 means that no job has been assigned.
* Note that these routines depend on j_rjobs and j_wjobs being 0 initially.
*/
struct jobs {
int (*j_rjob)();
int (*j_wjob)();
int j_arg;
};
/*
* The structure for the capacity call. There is an array of these,
* one element per fd for which it is desired to take the capacity.
* The fds are then used to index into the jobs array.
*/
struct capacities {
int fdcapac;
int c_read;
int c_write;
};
/*
* The structure for the non-capacity-controlled routines.
* These routines operate entirely independently.
*/
struct others {
int (*o_job)();
int o_arg;
};
/* -------------------------- I O E N T E R ------------------------- */
/*
* IoEnter(fd, rfunc, wfunc, arg) enters a file descriptor and its
* read and write handlers into the "io queue". When there is activity
* on the file descriptor, the handler is called with three arguments:
* the file descriptor, the capacity, and the arg supplied in the enter
* call. If the handler is 0, it is not called.
* The handler must return 0 if it did work, or a nonzero value
* if there was no work for it to do.
*/
IoEnter(fd, rfunc, wfunc, arg)
int fd;
int (*rfunc)();
int (*wfunc)();
int arg;
{
extern int errno;
struct jobs *jp;
extern struct jobs jobs[];
extern struct capacities capacities[];
extern int njobs;
extern int restart;
if (fd < 0 || fd >= NOFILE)
fatal(0, "IoEnter: bad fd %d\n", fd);
jp = &jobs[fd];
if (njobs >= MAXJOBS)
fatal(0, "Unable to enter fd %d", fd);
if (awtenb(fd) == -1)
if (errno != EBADDEV)
fatal(errno, "await-enabling %d", fd);
capacities[njobs++].fdcapac = fd;
jp->j_rjob = rfunc;
jp->j_wjob = wfunc;
jp->j_arg = arg;
restart = 1;
return;
}
/* -------------------------- I O X E N T E R ----------------------- */
/*
* IoxEnter(funcp, arg) is similar to IoEnter but is designed for routines
* for which taking the capacity of a fd is unnecessary or meaningless.
* The routine will be called as follows:
* active_sw = (*funcp)(arg);
* active_sw and arg are as for routines called by IoEnter.
*
* Note that routines supplied to IoxEnter will always be called whenever
* there is activity on any other routine.
*/
IoxEnter(fp, arg)
int (*fp)();
int arg;
{
extern int nothers;
extern struct others others[];
if (nothers >= MAXOTHERS)
fatal(0, "Unable to enter Iox job");
others[nothers].o_job = fp;
others[nothers].o_arg = arg;
nothers++;
}
/* -------------------------- I O D E L E T E ----------------------- */
/*
* IoDelete(fd) deletes a file descriptor and its handler from the queue.
* Note that, because the capacities structure is fed directly to the
* capac system call, the structure must be kept "clean" (active entries
* after the deleted one are moved up).
*/
IoDelete(fd)
int fd;
{
register int i;
extern int errno;
struct jobs *jp;
extern struct jobs jobs[];
extern struct capacities capacities[];
extern int restart;
extern int njobs;
for (i = 0; i < njobs; i++)
if (capacities[i].fdcapac == fd)
{
awtdis(fd);
capacities[i].fdcapac = -1;
for (; i < njobs-1; i++)
capacities[i].fdcapac = capacities[i+1].fdcapac;
njobs--;
jp = &jobs[fd];
jp->j_wjob = 0;
jp->j_rjob = 0;
jp->j_arg = 0; /* Not that it matters... */
restart = 1;
return;
}
com_err(0, "IoDelete: cannot find %d\n", fd);
return;
}
/* -------------------------- I O X D E L E T E --------------------- */
/*
* IoxDelete(funcp, arg) is similar to IoDelete but is for routines entered
* via IoxEnter.
*/
IoxDelete(fp, arg)
int (*fp)();
int arg;
{
register int i;
extern int nothers;
extern struct others others[];
for (i = 0; i < nothers; i++)
{
if ((others[i].o_job == fp) && (others[i].o_arg == arg))
{
others[i].o_job = 0;
others[i].o_arg = 0;
for (nothers--; i < nothers; i++)
{
others[i].o_job = others[i+1].o_job;
others[i].o_arg = others[i+1].o_arg;
}
return;
}
}
com_err(0, "IoxDelete: cannot find 0%o 0%o\n", fp, arg);
return;
}
/* -------------------------- I O R U N --------------------------- */
/*
* IoRun(awttim) is called to actually do the work. It does not return;
* it continually does capacity calls and calls the appropriate
* routines. When there is no work to do, it awaits for awttim seconds.
*/
IoRun(awttim)
int awttim;
{
int fd;
int (*f)();
int inactive, i;
struct capacities *cp;
struct jobs *jp;
struct others *op;
extern int errno;
extern struct jobs jobs[];
extern struct capacities capacities[];
extern int njobs;
extern int restart;
extern struct others others[];
extern int nothers;
for (;;)
{
inactive = 1;
RETRY:
restart = 0;
errno = 0;
if (capac(-1, capacities, njobs * sizeof(capacities[0])) == -1)
if (errno == EINTR) /* Just a signal */
goto RETRY;
else
fatal(errno, "Getting capacities");
for (cp = &capacities[0]; cp < &capacities[njobs]; cp++)
{
fd = cp->fdcapac;
if (fd < 0) /* Replaced by negative of error code */
fatal(-fd, "Getting a capacity, cannot continue");
jp = &jobs[fd];
if ((f = jp->j_wjob) && cp->c_write != 0)
{
i = (*f)(fd, cp->c_write, jp->j_arg);
if (inactive) inactive = i;
if (restart) goto RETRY; /* Func called IoEnter or IoDelete */
}
if ((f = jp->j_rjob) && cp->c_read != 0)
{
i = (*f)(fd, cp->c_read, jp->j_arg);
if (inactive) inactive = i;
if (restart) goto RETRY;
}
}
for (op = &others[0]; op < &others[nothers]; op++)
{
i = (*(op->o_job))(op->o_arg);
if (inactive) inactive = i;
}
if (inactive)
{
if (await(awttim, 0, 0) == -1)
if (errno != EINTR) /* Signal during await just takes us out */
fatal(errno, "in await");/* Any other problem and we die */
}
}
}
/* -------------------------- G L O B A L S ------------------------- */
struct jobs jobs[NOFILE];
struct capacities capacities[MAXJOBS];
int njobs 0; /* Number of active entries in capacities array */
int restart 0;/* Set when IoEnter or IoDelete called -- makes IoRun retry */
struct others others[MAXOTHERS];
int nothers 0; /* Number of active entries in others array */