Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: utzoo!mnetor!uunet!seismo!ut-sally!hitchens
From: hitchens@ut-sally.UUCP (Ron Hitchens, TP Repairman)
Newsgroups: comp.unix.questions
Subject: Re: Keyboard Input (Revised Question) ...
Message-ID: <8578@ut-sally.UUCP>
Date: Tue, 28-Jul-87 01:33:23 EDT
Article-I.D.: ut-sally.8578
Posted: Tue Jul 28 01:33:23 1987
Date-Received: Wed, 29-Jul-87 04:09:29 EDT
References: <1043@bucsb.bu.edu.UUCP> <8569@ut-sally.UUCP> <1021@ius1.cs.cmu.edu>
Reply-To: hitchens@godzilla.cs.utexas.edu (Ron Hitchens)
Organization: Syscalls R Us
Lines: 129
Keywords: Keyboard
Summary: use select() when appropriate

In article <1021@ius1.cs.cmu.edu> edw@ius1.cs.cmu.edu (Eddie Wyatt) writes:
}In article <8569@ut-sally.UUCP>, hitchens@godzilla.cs.utexas.edu (Ron Hitchens, Sun Wiz) writes:
}> ...this is a job for select()...
 
}   If your talking about my posting of "ready_to_read" for determining
}if a characters are ready to read, there is a reason why it doesn't used
}"select". Plain in simple, select is a dog of a system call.  When I measure
}the time it takes to call both select and ioctl on a fd associated with a
}socket, I found ioctl FNREAD to be about 3 times as fast. 

   Ya gotta point, Eddie.  Select does indeed incur quite a bit more overhead
than an ioctl does.  Though in fairness select is more flexible and works
at a higher level than an ioctl does.  In looking at this again, I think I
made an assumption that the code would want to do periodic processing, while
also watching the keyboard for input.  This may not be the case, if you
want to spend as much time as possible computing, but also notice that
a key has been pressed, using a FIONREAD ioctl is quicker and less 
expensive.

   But if you want to go to sleep until either something is ready to read
or a time interval expires, select is clearly better.  This is in fact
multiplexing, multiplexing a timer and an fd.  This is a big win over 
polling loops for that sort of thing.
 
}  To the orignal poster,  you want to run both read_to_read or select with
}CBREAKs on.

   Yeah, and remember to reset the tty modes before you exit.  You may also
want to catch INT and QUIT signals so that you can reset the modes if
you're interrupted.
   
}   BTW select is only better than ioctl for determining if a SINGLE port
}has characters on it to read from, in that you can specify a time out value if
}needed.  May I also sugguest you read the man page entry for "select".  The
}synopsis specificly says the call is intended  for multiplexing.  Polling a
}single line doesn't constitute multiplexing, through the system call  "select"
}can obviously be used for such operations.

   Agreed.  Polling an fd with a timeout is what I had in mind.  This is
not always what is desired, but is a good coding practice for interactive
applications.  It allows you to surrender control to the kernel, so that
other processes can run, and have it wake you up when one of two (or more)
conditions is met.  Again, I agree that select is not a good choice for doing
a straight poll on a single fd, though it can be done.  A direct ioctl is
less expensive for that.

}> loop ()
}> {
}> 	static	struct	timeval	timer = {REFRESH_DEFAULT, 0};
}> 	char	c;
}> 	int inmask, nfds;
}> 
}> 	timer.tv_sec = refresh_time;		/* settable on cmd line */
}> 	while (1) {
}> 		show_stat ();			/* do it */
}> 		inmask = 1;			/* gotta set the mask always */
}		^^^^^^^^^^^^^^^^^^^^
 
}		A mood point here.  If you are using BSD 4.2 this should be:
}		inmask = (1<<(fileno(stdout)));
}
}		In BSD 4.3 this should be :
}		{
}		fd_set inmask;
}		.....
}
}		FD_SET(fileno(stdout),&inmask);
}		.........
}		}

  Right, except that I'm using stdin, not stdout.  The hardcoded 1 (shame
on me!) is the bit for fd 0 which is (usually) stdin.  Sorry about that, this
is ancient code and I should know better.

}> 		if ((nfds = select (32, &inmask, 0, 0, &timer)) < 0) {
}> 			printf ("Error doing select, I'm gettin' outta here\n");
}> 			return;
}> 		}
}> 		if (nfds == 0)
}> 			continue;		/* timer expired */
}> 		read (0, &c, 1);		/* the sucker hit a key */
}		     ^^^^^^^^^^
}			Another mood point.  this should be -
}		read(fileno(stdout),&c,sizeof(char));

   Right again.  I really do code more portably now (honest).  This code is
from a program which is necessarily BSD specific (it looks at rwhod packets,
which is a hack only Berkeley could love), so I went ahead and harcoded those
fd values, a habit I've mostly broken now.  I could argue about sizeof(char),
in that I want to only read one byte, even if sizeof(char) wasn't 1, but it's
not worth it.

}			And if you are overly cautious
}
}		if ((readval = read(fileno(stdout),&c,sizeof(char))) == -1)
}			perror("read failed");
}		else if (readval == 0)
}			fprintf(stderr,"EOF encounter\n");

  I wasn't overcautious, I wanted to quit on the slightest excuse and leave.
If there was a read error or EOF, I'd exit through the switch statement,
though I should have cleared the character before reading.

}> 		switch (c) {
}> 		case 'r':
}> 		case 'R':
}> 		case 0x12:   /* ^R */
}> 		case 'l':
}> 		case 'L':
}> 		case 0x0C:   /* ^L */
}> 			(void) wclear (stdscr);	 /* clear the physical screen */
}> 			(void) wrefresh (stdscr);/* for reassuring feedback */
}> 			break;
}> 		default:
}> 			return;
}> 		}
}> 	}
}> }
}					Eddie Wyatt
}e-mail: edw@ius1.cs.cmu.edu

   I'm a little embarrassed by the number of nits to be picked in my sample
code, I should have cleaned it up before posting.  But anyway, I'm still
a fan of select, when used appropriately it can greatly simplify your life,
and achieving the same functionality without it is a major pain.


Ron Hitchens		hitchens@ut-sally.uucp
			hitchens@godzilla.cs.utexas.edu