Bug 71671 - If VTIME == 0 and VMIN == 0 nonblocking read returns 0 instead of EAGAIN.
Summary: If VTIME == 0 and VMIN == 0 nonblocking read returns 0 instead of EAGAIN.
Status: RESOLVED CODE_FIX
Alias: None
Product: Drivers
Classification: Unclassified
Component: Serial (show other bugs)
Hardware: All Linux
: P1 normal
Assignee: Peter Hurley
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-03-07 13:18 UTC by Ivan
Modified: 2014-03-21 13:49 UTC (History)
2 users (show)

See Also:
Kernel Version: linux-3.8.13
Subsystem:
Regression: No
Bisected commit-id:


Attachments

Description Ivan 2014-03-07 13:18:30 UTC
If VTIME == 0 and VMIN == 0, nonblocking read in noncanonical mode returns 0 instead of EAGAIN.

If VTIME == 0 and VMIN == 0, then timeout == time == 0 (see n_tty_read in n_tty.c).

===== tst1.c =====
#define _GNU_SOURCE

#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <unistd.h>

int fd = -1;

void doerror(char *Text)
{
	warn("%s", Text);
	if (fd != -1)
		close(fd);
	exit(0);
}

int main()
{
int i;
char c;
struct termios te;

	fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NONBLOCK);
	
	if (fd == -1)
		doerror("open");
	
	if (tcgetattr(fd, &te) == -1)
		doerror("tcgetattr");

	cfmakeraw(&te);
	te.c_iflag &= ~(IGNPAR | INPCK | IXANY | IXOFF);
	te.c_cflag &= ~(CSTOPB | PARENB | PARODD | CRTSCTS);
	te.c_cflag |= CREAD | HUPCL | CLOCAL;
	
	te.c_cc[VTIME] = 0;
	te.c_cc[VMIN] = 0;
	
	cfsetispeed(&te, B115200);
	cfsetospeed(&te, B115200);
	
	if (tcsetattr(fd, TCSANOW, &te) == -1)
		doerror("tcsetattr");

	i = read(fd, &c, 1);
	if (i == 0)
		fprintf(stderr, "read 0 bytes\n");
	else if (i < 0)
		doerror("read");
	else
		fprintf(stderr, "read 0x%.2X\r\n", (unsigned char)c);
	
	close(fd);
	
	return 0;
}
==================

When input is not available, input_available_p(tty, 0) returns 0 and the function also returns 0 instead of EAGAIN:
                        if (!timeout)
                                break;
                        if (file->f_flags & O_NONBLOCK) {
                                retval = -EAGAIN;
                                break;
                        }

Another bug (blocking read in noncanonical mode):
When TIME == 0, MIN == e.g. 5, and read is called with count == 3 (see tst2.c), then read blocks until 5 (not 3) chars received. But if there are already 3 chars in the buffer, then read returns immediately. Is it correct?

===== tst2.c =====
#define _GNU_SOURCE

#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <unistd.h>

int fd = -1;

void doerror(char *Text)
{
	warn("%s", Text);
	if (fd != -1)
		close(fd);
	exit(0);
}

int main()
{
int i, j;
char buf[256];
struct termios te;

	fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NONBLOCK);
	
	if (fd == -1)
		doerror("open");

	int Result = fcntl(fd, F_GETFL);
	if (Result != -1)
		Result = fcntl(fd, F_SETFL, Result & ~O_NONBLOCK);
	
	if (tcgetattr(fd, &te) == -1)
		doerror("tcgetattr");

	cfmakeraw(&te);
	te.c_iflag &= ~(IGNPAR | INPCK | IXANY | IXOFF);
	te.c_cflag &= ~(CSTOPB | PARENB | PARODD | CRTSCTS);
	te.c_cflag |= CREAD | HUPCL | CLOCAL;
	
	te.c_cc[VTIME] = 0;
	te.c_cc[VMIN] = 5;
	
	cfsetispeed(&te, B115200);
	cfsetospeed(&te, B115200);
	
	if (tcsetattr(fd, TCSANOW, &te) == -1)
		doerror("tcsetattr");

	printf("--- You can send chars. Press Enter ---\n");
	getchar();

	i = read(fd, buf, 3);
	if (i == 0)
		fprintf(stderr, "read 0 bytes\n");
	else if (i < 0)
		doerror("read");
	else
	{
		fprintf(stderr, "Result = %d\n", i);
		for (j = 0; j < i; j++)
			fprintf(stderr, "read 0x%.2x\n",
			(unsigned char)buf[j]);
	}
	
	close(fd);
	
	return 0;
}
==================

If TIME == 0, MIN > 0 then tty->minimum_to_wake = minimum and n_tty_receive_buf wakes after 5 chars (see n_tty.c).
Comment 1 Peter Hurley 2014-03-20 14:46:00 UTC
(In reply to Ivan from comment #0)
> If VTIME == 0 and VMIN == 0, nonblocking read in noncanonical mode returns 0
> instead of EAGAIN.

Not a bug.

POSIX does not specify if O_NONBLOCK takes precedence over the MIN/TIME settings.
The Linux interpretation is that it does not.

> Another bug (blocking read in noncanonical mode):
> When TIME == 0, MIN == e.g. 5, and read is called with count == 3 (see
> tst2.c), then read blocks until 5 (not 3) chars received. But if there are
> already 3 chars in the buffer, then read returns immediately. Is it correct?

There is no specification or guidance in this situation.

However, I believe that read() in non-canonical mode should always complete successfully if the number of bytes requested are available. IOW,

minimum_to_wake = min(minimum, nr);

Please let us know if you intend to send a patch.
Comment 2 Alan 2014-03-20 15:09:47 UTC
VMIN/VTIME behaviour is basically defined by "What does Systen 5.x do". In which case we are correct already. 

On the former VMIN/VTIME behaviour returning 0 matches other OS behaviour. 

I don't think we should change behaviour here

Alan
Comment 3 Peter Hurley 2014-03-20 15:23:37 UTC
(In reply to Alan from comment #2)
> I don't think we should change behaviour here

I guess maybe I wasn't clear enough in my comment (which is made worse by the initial report containing 2 separate bug reports).

1st report (TIME==0, MIN==0, O_NONBLOCK in non-canonical mode):
Not a bug, nothing to do here.

2nd report (TIME==0, MIN==5, read(fd, &buf, 3)):
I think it makes sense to wake up and complete the read() if 3 chars are received (since if there are already 3 chars in the input buffer we will complete the read() regardless of the MIN setting).
Comment 4 Alan 2014-03-20 15:33:49 UTC
You can argue it either way. In fact MacOS X explicitly does one and Solaris explicitly does the other. We follow the SYS5 behaviour.

We shouldn't change that behaviour between two differently random responses to an arguably bogus request. Changing it is more damaging than consistency of existing behaviour

Alan
Comment 5 Peter Hurley 2014-03-20 15:43:15 UTC
> We follow the SYS5 behaviour.

Ok.
Comment 6 Ivan 2014-03-20 16:02:20 UTC
I think that you know better, as it should be but

1. "man termios" says nothing about TIME/MIN behaviour with O_NONBLOCK in non-canonical mode. I think that it should be added to man that read can return 0, not EAGAIN with TIME==0, MIN==0. The user should not forget to set MIN=1!

2. "man termios" says "MIN > 0; TIME == 0: read(2) blocks until the lesser of MIN bytes or the number of bytes requested are available, and returns the lesser of these two values" Deside for yourself...
Comment 7 Ivan 2014-03-20 16:16:32 UTC
1. Addition.

Independently of POSIX standard I must be sure in read-function behaviour.

E. g.

select(ComPort, ...);

... Wait until data received ...

read(...);

... Process read data ...

read(...);

If read returned 0, it means that there is no data or the connection was hung up?
Comment 8 Peter Hurley 2014-03-20 16:33:17 UTC
(In reply to Ivan from comment #6)
> I think that you know better, as it should be but
> 
> 1. "man termios" says nothing about TIME/MIN behaviour with O_NONBLOCK in
> non-canonical mode. I think that it should be added to man that read can
> return 0, not EAGAIN with TIME==0, MIN==0. The user should not forget to set
> MIN=1!
> 
> 2. "man termios" says "MIN > 0; TIME == 0: read(2) blocks until the lesser
> of MIN bytes or the number of bytes requested are available, and returns the
> lesser of these two values" Deside for yourself...

I will clarify both of these points with Michael Kerrisk.

I had already noticed #2 is wrong anyway: read() will return up to the number of bytes requested regardless of the MIN value, as long as that is >= min(MIN,nr).

For example, if MIN==5 and nr==300, and input available is 1000, read() will
return 300, not 5.

Even if input available *at the time* was only just 5, by the time the read() is woken, if more input has become available, it will be returned, provided the total amount is not larger than nr.
Comment 9 Peter Hurley 2014-03-20 17:24:49 UTC
(In reply to Ivan from comment #7)
> 1. Addition.
> 
> Independently of POSIX standard I must be sure in read-function behaviour.
> 
> E. g.
> 
> select(ComPort, ...);
> 
> ... Wait until data received ...
> 
> read(...);
> 
> ... Process read data ...
> 
> read(...);
> 
> If read returned 0, it means that there is no data or the connection was
> hung up?

Only blocking reads (canonical mode or MIN>0, TIME=0 in non-canonical mode)
return 0 to indicate EOF (tty was hungup).

All ioctl()'s on the tty will return EIO if the tty was hungup.
Specifically,

     err = ioctl(fd, FIONREAD, &bytes_avail);

is the most common way to determine the status of the tty after select() or poll().

[NB: this advice does not apply if this is about large numbers of file descriptors. Use either epoll or signal-driven i/o in these cases.]
Comment 10 Michael Kerrisk 2014-03-21 13:49:01 UTC
(In reply to Alan from comment #2)
> VMIN/VTIME behaviour is basically defined by "What does Systen 5.x do". In
> which case we are correct already. 

Actually, that may not quite be true. Take a look at POSIX.1-2008 XBD 11.1.7, and then see this text I just drafted for the termios(3) man page:

       MIN > 0; TIME > 0:
              TIME specifies the limit for a timer in tenths of  a  sec‐
              ond.  Once an initial byte of input becomes available, the
              timer is restarted after each further  byte  is  received.
              read(2)  returns  when  any of the following conditions is
              met:

              *  MIN bytes have been received.

              *  The interbyte timer expires.

              *  The number of  bytes  requested  by  read(2)  has  been
                 received.   (POSIX  does  not  specify this termination
                 condition, and on  some  other  implementations  read()
                 does not return in this case.)

Solaris, for example, doesn't terminate the read() in the final case. Presumably, Solaris is truly following System V (and Linux is not).

On the other hand, it would not surprise me to find that the Linux behavior has been present since near the beginning, and no one seems to have minded enough to do anything about it (after all, having MIN be > number of bytes requested in read() is kind of odd).

Note You need to log in before you can comment on or make changes to this bug.