Timed reading in C (?)

Larry Philps larry at hcr.UUCP
Thu Feb 18 00:37:55 AEST 1988


In article <469 at mv02.ecf.toronto.edu> ip at mv02.ecf.UUCP (Bevis Ip) writes:
>>What I want my program to do is wait a short while (like, say, 5 seconds
>>or so) for an user to type in something. If the user doesn't type in
>>anything after that time period, the program goes ahead and does something
>>else. But if the user has already started to type, the program waits and
>>lets him finish typing.
>>
>>What I'd like to know is how to do this in C. (By the way, I'm on BSD
>>Unix 4.3.) I want the user's terminal to stay in the canonical mode,
>>if possible.
>
>Took me a while to crank the following program up, seems like it's doing
>what you've asked. There're probably better ways in doing this, and I'm
>open for criticism. The code is pretty straight forward (I hope), so
>comments are minimal.
>
>bevis
>
>  Program using signals, setjmp, longjmp ...

This can be done a little easier.  The following two incomplete programs
should show you how.  Since I did not write complete programs, I have
obviously not tested them, but you should get the idea.

/*
 * Solution 1: Use select to wait for a specified period for input.
 * When select returns, either the timeout has expired, or there is
 * data to read.  React appropriately.
 */

	int		fd, nbytes, nfound;
	char		buf[BUFFER_SIZE];
	fdset		readfds;
	struct	timeval	timeout;

	/*
	 * either this if reading standard input, or
	 * open the appropriate file and get a file
	 * descriptor for it.
	 */
	fd = 0;

	FD_ZERO(&readfds);
	FD_SET(fd, &readfds);
	timeout.tv_sec = SLEEP_TIME;
	timeout.tv_usec = 0;

	nbytes = 1;
	while (nbytes != 0) { /* End of File test */
		nfound = select (1, &readfds, (int *)0, (int *)0, &timeout);
		if (nfound < 0) {
			perror("select");
			exit(1);
		}
		if (nfound == 0) {
			/*
			 * The timeout expired.  There is no data to read
			 * so do what needs to be done in this case.
			 */
			.....
			continue;
		}

		/*
		 * Select did not return an error, and the timeout did not
		 * expire.  There must be data to read on the only file
		 * descriptor we told it to watch.
		 */
		ASSERT(FD_ISSET(fd, &readfds));
		nbytes = read(fd, buf, sizeof(buf));
		/*
		 * We have the data.  Do something.
		 */
		...
	}

/*
 * Solution 2: Use non-blocking I/O so that the reads never hang.
 * This has the disadvantage that if there is no data to read, then
 * you sleep before trying again, thus creating a possible lag time
 * between the time that the user types his input and the program sees
 * it.  The advantage is that it does not use select (an advantage you say!)
 * and thus should even work on System V.
 */

	int	fd, nbytes;
	char	buf[BUFFER_SIZE];

	/*
	 * either this if reading standard input, or
	 * open the appropriate file and get a file
	 * descriptor for it.
	 */
	fd = 0;

	if (fcntl (fd, F_SETFL, FNDELAY) < 0) {
		perror("fcntl: F_SETFL");
		exit(1);
	}

	/*
	 * Give the user a chance to type something first.
	 * This is grotty.
	 */
	sleep(SLEEP_TIME);

	/*
	 * Now non-blocking I/O is enabled on the file descriptor.
	 * Reads will not hang, so try one and if there is no data
	 * just sleep for a bit, then try again.
	 */
	while ((nbytes = read(fd, buf, sizeof(buf)) != 0) {
		if (nbytes < 0 && errno == EWOULDBLOCK) {
			/*
			 * No data for us now, do what needs to be done
			 * when the user has entered no input, then
			 * try again later.
			 */
			...
			sleep(SLEEP_TIME);
			continue;
		}
		/*
		 * We have the data.  Do something.
		 */
		...
	}
----
Larry Philps                             HCR Corporation
130 Bloor St. West, 10th floor           Toronto, Ontario.  M5S 1N5
(416) 922-1937                           {utzoo,utcsri,decvax,ihnp4}!hcr!larry



More information about the Comp.unix.questions mailing list