Need Non-Blocking Terminal Input Function For Berkeley 4.2

Steve D. Miller steve at umcp-cs.UUCP
Mon Jan 27 04:25:16 AEST 1986


In article <482 at kontron.UUCP> cramer at kontron.UUCP writes:
>Does anyone know of a way to do read from a terminal under Berkeley 4.2 UNIX
>so that after a specified number of seconds control is returned to the
>program if there is no response?  ...


   Methinks that what you want to use is select(2).  Something similar to
what I think you want to do would probably look like:

#include <sys/time.h>		/* for struct timeval */
 ...
struct timeval timeout;
int s, readfds, nfound;			/* s = fd we want to look at */
...
timeout.tv_sec = <number of secs to wait>;
timeout.tv_usec = <number of microseconds to wait in addition to above>
readfds = 1 << s;		/* form bit mask */
/*
 * This will time out after the period specified in timeout
 * (and return zero in &readfds), or return before that with
 * nfound == 1 and (1 << s) set in readfds).  See the man entry
 * for more details; select() falls into the category of
 * "really massively useful system calls that you want to
 * know about".
 */
nfound = select(32, &readfds, (int *) 0, (int *) 0, &timeout);
if (nfound < 0) {
	/* error */
}
if (nfound > 0) {
	/* got something */
	read(s, buf, <whatever you want>);
	...
}
else {
	/* whatever happens when you don't get input */
}

   In general, select() will let you multiplex input over a number of file
descriptors in which you are interested in reading from, writing to, or
knowing about "exceptional conditions" (means nothing in 4.2, though I could
be wrong, but means at least "out-of-band data" in 4.3) on.  If you're
select()ing on more than one descriptor, then you want to check the
returned bit masks (i.e., "if (readfds & (1 << s)) { ..  }) for each
descriptor you're interested in; the above example is simplified since it
deals with only one descriptor.

   Note (for those of you who are interested) that all this changes in
4.3BSD.  The above code will still work, but is no longer correct.  Since
there are more than 32 fds available, a more general scheme has been
devised, using struct fd_set's (which are really just arrays of integer bit
masks, though you don't need to know that; they're defined in <sys/types.h>,
and can also be referred to as fd_sets, since they're typedef'ed).  Four
macros are defined for use in manipulating fd_sets:  FD_SET(n, p), which
adds fd n to the fd_set pointed to by p; FD_CLR(n, p), which removes fd n
from the fd_set pointed to by p; FD_ISSET(n, p), which returns an indication
of whether or not fd n is a member of the fd_set pointed to by p; and
FD_ZERO(p), which clears the fd_set pointed to by p.  Therefore, the code
above would, under 4.3BSD, look like:

#include <sys/types.h>
#include <sys/time.h>		/* for struct timeval */
 ...
struct timeval timeout;
int s, nfound;			/* s = fd we want to look at */
fd_set readfds;
...
timeout.tv_sec = <number of secs to wait>;
timeout.tv_usec = <number of microseconds to wait in addition to above>
FD_ZERO(&readfds);
FD_SET(s, &readfds);
/*
 * This will time out after the period specified in timeout
 * (and return readfds with no bits set), or return before that with
 * nfound == 1 and FD_ISSET(s, &readfds) == true.  See the man entry
 * for more details; select() falls into the category of
 * "really massively useful system calls that you want to
 * know about".
 */
nfound = select(32, &readfds, (fd_set *) 0, (fd_set *) 0, &timeout);
if (nfound < 0) {
	/* error */
}
if (nfound > 0) {
	/* got something */
	read(s, buf, <whatever you want>);
	...
}
else {
	/* whatever happens when you don't get input */
}

   Again, if we were select()ing on more than one descriptor, we'd
want to check the status of the returned fd_set with FD_ISSET, since
the number of fds available for reading (as indicated by nfound) would
in that case not indicate that we could read off of any given fd.

   I hope this is of some use (to you or to someone else)...

	-Steve



More information about the Comp.unix.wizards mailing list