How to implement a timeout in read() function call?

CLinux

C Problem Overview


I want to use serial com port for communication and I want to implement a timeout every time I call the read() function call.

int filedesc = open( "dev/ttyS0", O_RDWR );

read( filedesc, buff, len );

EDIT:

I'm using Linux OS. How to implement using select function call?

C Solutions


Solution 1 - C

select() takes 5 parameters, first the highest file descriptor + 1, then a fd_set for read, one for write and one for exceptions. The last parameter is a struct timeval, used for timeout. It return -1 on error, 0 on timeout or the number of file descriptors in the sets that are set.

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>

int main(void)
{
  fd_set set;
  struct timeval timeout;
  int rv;
  char buff[100];
  int len = 100;
  int filedesc = open( "dev/ttyS0", O_RDWR );

  FD_ZERO(&set); /* clear the set */
  FD_SET(filedesc, &set); /* add our file descriptor to the set */

  timeout.tv_sec = 0;
  timeout.tv_usec = 10000;

  rv = select(filedesc + 1, &set, NULL, NULL, &timeout);
  if(rv == -1)
    perror("select"); /* an error accured */
  else if(rv == 0)
    printf("timeout"); /* a timeout occured */
  else
    read( filedesc, buff, len ); /* there was data to read */
  close(filedesc);
}

Solution 2 - C

As an alternative to select(), for the specific case of a serial port (terminal) you can use tcsetattr() to put the file descriptor into non-canonical mode, with a read timeout.

To do this, unset the ICANON flag, and set the VTIME control character:

struct termios termios;

tcgetattr(filedesc, &termios);
termios.c_lflag &= ~ICANON; /* Set non-canonical mode */
termios.c_cc[VTIME] = 100; /* Set timeout of 10.0 seconds */
tcsetattr(filedesc, TCSANOW, &termios);

Note VTIME is measured in tenths of a second, and that the type used for it is typically an unsigned char, meaning that the maximum timeout is 25.5 seconds.

Solution 3 - C

If you set the socket do operate in non-blocking mode, each call to read will read only the data currently available (if any). So this is effectively equal to an immediate timeout.

You can set non-blocking mode on a socket with a function like this:

int setnonblock(int sock) {
   int flags;
   flags = fcntl(sock, F_GETFL, 0);
   if (-1 == flags)
      return -1;
   return fcntl(sock, F_SETFL, flags | O_NONBLOCK);
}

(For more information about reading from non-blocking sockets see the read man page)

Solution 4 - C

You don't say what the OS is but if you're running under Linux, you could use the select call. It returns if there is something to read on the file descriptor or you can set it up so that it will timeout if there is nothing to read. The return code indicates which.

Solution 5 - C

The code below uses millisec timeouts per character. I use it in one of my project to read from COM port.

size_t TimeoutRead (int port, void*buf, size_t size, int mlsec_timeout)
{
	struct pollfd fd = { .fd = port, .events = POLLIN };

	size_t		bytesread = 0;

	while (poll (&fd, 1, mlsec_timeout) == 1)
	{
		int chunksize = read (port, buf + bytesread, size);
		if (chunksize == -1)
			return -1;

		bytesread += chunksize;
		size -= chunksize;

		if (size == 0)
			return bytesread;
	}

	// TODO: IsTimeout = true;
	return bytesread;
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiondomlaoView Question on Stackoverflow
Solution 1 - CPuppeView Answer on Stackoverflow
Solution 2 - CcafView Answer on Stackoverflow
Solution 3 - CsthView Answer on Stackoverflow
Solution 4 - CsizzzzlerzView Answer on Stackoverflow
Solution 5 - Crick-rick-rickView Answer on Stackoverflow