[pe.cust.wanted] inputpending

dave@lsuc.UUCP (David Sherman) (03/27/85)

I asked in net.lang.c for a mechanism for FIONREAD (non-blocking
read) for v7, and the following was posted in reply:

=From: sjoerd@tjalk.UUCP (Sjoerd Mullender)
=Message-ID: <443@tjalk.UUCP>
=Date: 21 Mar 85 13:00:48 GMT
=Organization: VU Informatica, Amsterdam
=
=Here is a C routine that returns non-zero if there was any input pending.
=This is for a V7 PDP 11 system.  The only requirement is that /dev/kmem
=is readable (which it should NOT be for security).
=
=#include <sys/param.h>
=#include <sys/dir.h>
=#include <sys/user.h>
=
=inputpending()
={
=	static int fd = -2;
=	unsigned c;
=
=	if (fd == -2)	/* uninitialized */
=		if ((fd = open("/dev/kmem", 0)) >= 0) {
=			/* If the open fails, fd will be -1, so we won't
=			 * try again.
=			 * Close the file descriptor on exec.
=			 */
=			ioctl(fd, FIOCLEX, (struct sgttyb *) 0);
=			/* 0140000 is the beginning of the u area
=			 * u_ttyp is the pointer to the tty struct
=			 */
=			lseek(fd, (long) &((struct user *) 0140000)->u_ttyp, 0);
=			read(fd, &c, sizeof c);
=			/* seek to the beginning of the tty struct */
=			lseek(fd, (long) c, 0);
=		}
=	if (fd < 0)
=		return 0;
=	/* the first 2 byte of the tty struct is a pointer to the clist */
=	if (read(fd, &c, sizeof c) < sizeof c)
=		return 0;
=	lseek(fd, - (long) sizeof c, 1);
=	/* there is input when the pointer to the clist is != 0 */
=	return c != 0;
=}

I figured out that the 0140000 should be changed to 0xff0000, or
actually UBASE, which is defined in param.h. But when I tried
compiling this with a test program
	main()
	{
		while(1)
		{
			if(inputpending())
				printf("something\n");
			else
				printf("nothing\n");
			sleep(1);
		}
	}
it always prints "nothing". I changed the unsigned c to int c,
to correspond to the tty.h definition, and that didn't help either.

What am I doing wrong. How can I get this to work? It would be
very helpful for a number of programs, including rn.

Dave Sherman
-- 
{utzoo pesnta nrcaero utcs hcr}!lsuc!dave
{allegra decvax ihnp4 linus}!utcsri!lsuc!dave

tim@per.UUCP (Tim Pointing) (03/28/85)

I tried the version of inputpending posted recently by Dave Sherman (dave@lsuc)
and, after making the 0140000 <=> UBASE correction and including <sys/tty.h>
(required for FIOCLEX), inputpending worked just fine. I have confidence that
this is not due to the modified tty driver that we are running here. Included
below is the exact source for the test that I ran...


> main()
> {
> 	while(1)
> 	{
> 		if(inputpending())
> 			printf("something\n");
> 		else
> 			printf("nothing\n");
> 		sleep(1);
> 	}
> }
> 
> #include <sys/param.h>
> #include <sys/dir.h>
> #include <sys/user.h>
> #include <sys/tty.h>
> 
> inputpending()
> {
> 	static int fd = -2;
> 	unsigned c;
> 
> 	if (fd == -2)	/* uninitialized */
> 		if ((fd = open("/dev/kmem", 0)) >= 0) {
> 			/* If the open fails, fd will be -1, so we won't
> 			 * try again.
> 			 * Close the file descriptor on exec.
> 			 */
> 			ioctl(fd, FIOCLEX, (struct sgttyb *) 0);
> 			/*
> 			 * u_ttyp is the pointer to the tty struct
> 			 */
> 			lseek(fd, (long) &((struct user *) UBASE)->u_ttyp, 0);
> 			read(fd, &c, sizeof c);
> 			/* seek to the beginning of the tty struct */
> 			lseek(fd, (long) c, 0);
> 		}
> 	if (fd < 0)
> 		return 0;
> 	/* the first int of the tty struct is a pointer to the clist */
> 	if (read(fd, &c, sizeof c) < sizeof c)
> 		return 0;
> 	lseek(fd, - (long) sizeof c, 1);
> 	/* there is input when the pointer to the clist is != 0 */
> 	return c != 0;
> }

Hope this works for you.

Dave - is this not exactly what you have?

For those lucky enough to have source, you can very easily add an ioctl call
similar to the Berkley FIONREAD, as we have done here, which functions for
tty's. If anybody wants that code, drop me a line - its only a couple of lines
of code.

---
Tim Pointing, DCIEM
{utzoo!dciem,lsuc,pesnta}!per!tim

danny@itm.UUCP (Danny) (03/29/85)

In article <549@lsuc.UUCP> dave@lsuc.UUCP (David Sherman) writes:
>I asked in net.lang.c for a mechanism for FIONREAD (non-blocking
>read) for v7, and the following was posted in reply...

    Dave, the following is a program that works on our system,
a P-E 3210, running edition7 (version 2.4) (right now).

    There isn't much more to making it into a function that will
return the number of chars waiting, the hardest thing is determining the
index into the "vdu" array.  You can do that by doing an fstat(2)
on fd 0, 1, 2 (whichever is the terminal), getting the minor device
number from fstat.st_rdev (minor is a macro in <sys/types.h>) as
the index into vdu.  Like:

    fstat (1, &sbuf);
    i = minor (sbuf.st_rdev);
    if (i >= 0 && i < MAXTTY)
        return vdu[i].t_rawq.c_cc;
    else
        return 0;

    Boy, that was a screenful!  Let's see if I can do it again;
with the program this time:

X# include <sys/types.h>
X# include <sys/tty.h>
X# include <a.out.h>
X
X# define NAME       "cic"      /* char input count */
X# define UNIX       "/edition7"
X# define MAXTTY     24
X# define MEM        "/dev/mem"
X# define READ       0
X# define BEG        0
X
Xstruct nlist nl[] = {
X    "vdu", 0, 0,
X    "", 0, 0,
X};
X
Xstruct tty vdu[MAXTTY];    /* should be gotten from /usr/sys/conf/para.c */
X
Xmain ()
X{
X    int i, fd;
X
X    nlist (UNIX, nl);
X    if (nl[0].n_type == 0 && nl[0].n_value == 0) {
X        printf ("%s: nlist failed.\n", NAME);
X        exit (-1);
X    }
X    fd = openf (MEM, READ, NAME);
X    for (;;) {
X        lseek (fd, (long) nl[0].n_value, BEG);
X        readf (fd, (char *) &vdu, sizeof (vdu), NAME, UNIX);
X        for (i = 0; i < 6; i++)
X            printf ("tty[%d] raw cnt is %d\n", i, vdu[i].t_rawq.c_cc);
X        sleep (4);
X    }
X}
X
X# include <stdio.h>
X
X/* openf --- open a file. Die if error. */
X
Xopenf (fname, mode, cname)
Xregister char *fname, *cname;
Xregister int mode;
X{
X    register int fd;
X    extern int errno;
X    extern char *sys_errlist[];
X
X    if ((fd = open (fname, mode)) < 0) {
X        fprintf (stderr, "%s: can't open %s (%s)\n", cname, fname,
X          sys_errlist[errno]);
X        exit (-1);
X    }
X    return (fd);
X}
X
X/* readf --- read n chars from file fd to buf. Die if error. */
X
Xreadf (fd, buf, nc, cname, fname)
Xregister int fd, nc;
Xregister char *fname, *buf, *cname;
X{
X    register int nread;
X    extern int errno;
X    extern char *sys_errlist[];
X
X    nread = read (fd, buf, nc);
X    if (nread != nc) {
X        fprintf (stderr, "%s: read %d bytes from %s, wanted %d (%s)\n",
X          cname, nread, fname, nc, sys_errlist[errno]);
X        exit (-1);
X    }
X}

    Well, I'd better shut up now.  I didn't realize how long-winded
a simple program can be...

    Hope this helps.

                                            Danny
-- 
				Daniel S. Cox
				({gatech|akgua}!itm!danny)

dave@lsuc.UUCP (David Sherman) (03/30/85)

I tried Tim's version (it was identical to what I'd tried
previously) and no, it doesn't work.... or am I missing something?
I run a.out, it prints a succession of nothings, I type some junk
at the terminal, and still nothings, no somethings! I press RETURN,
and still nothings...

Dave Sherman
-- 
{utzoo pesnta nrcaero utcs hcr}!lsuc!dave
{allegra decvax ihnp4 linus}!utcsri!lsuc!dave