Bug 107649
Summary: | ioctl not returning number of bytes in /dev/ttyS0 | ||
---|---|---|---|
Product: | Red Hat Enterprise Linux 3 | Reporter: | Scott Weathers <sweathers> |
Component: | kernel | Assignee: | Arjan van de Ven <arjanv> |
Status: | CLOSED NOTABUG | QA Contact: | Brian Brock <bbrock> |
Severity: | medium | Docs Contact: | |
Priority: | medium | ||
Version: | 3.0 | CC: | dwmw2, jlamb |
Target Milestone: | --- | ||
Target Release: | --- | ||
Hardware: | i386 | ||
OS: | Linux | ||
Whiteboard: | |||
Fixed In Version: | Doc Type: | Bug Fix | |
Doc Text: | Story Points: | --- | |
Clone Of: | Environment: | ||
Last Closed: | 2003-10-23 12:28:44 UTC | Type: | --- |
Regression: | --- | Mount Type: | --- |
Documentation: | --- | CRM: | |
Verified Versions: | Category: | --- | |
oVirt Team: | --- | RHEL 7.3 requirements from Atomic Host: | |
Cloudforms Team: | --- | Target Upstream Version: | |
Embargoed: |
Description
Scott Weathers
2003-10-21 18:20:55 UTC
Sounds it's cheaper to pass O_NONBLOCK as open flag for the file descriptor so that the kernel will just return the pending bytes and doesnt' wait for more. Saves you a syscall..... Means you have to buffer though. IF you have fixed-size packets it's easier to wait till there's a whole packet, then read it. the example code reads the bytes one by one anyway.... Well yes, but that's because it's test code designed to count bytes and show the problem. Yes, this does look like FIONREAD is buggy, although I can't actually find a real definition of the expected behaviour of FIONREAD anywhere; SUSv2 doesn't admit to its existence. I can't imagine there being a case for FIONREAD returning anything but either the number of readable bytes or an error though. In the meantime, I'd suggest using O_NONBLOCK and either poll() or select(). Can a get a timeout of less than a 1 second with select? Waiting 1 second with the signal alarm is very expensive. I need to be able to timeout in few mili seconds if there are no btyes in the ttySO buffer. select in RHEL3 has a 10 msec granularity (this does mean that if you ask for 10ms you get AT LEAST 10ms, so on average 15ms) if you don't want to wait *at all* you can use O_NONBLOCK If you set the O_NONBLOCK flag with fcntl() as Arjan suggested, your read() call will return _immediately_ if there are no data available. At some point presumably your application is waiting for something to happen, rather than continuously looping and attempting to read.... that's where you'd be using select(), waiting for an event to happen on _any_ of the file descriptors you're interested in; not just the serial port. According to the man page the select() call allows you to specify a timeout in ....what Arjan just said :) I am using the O_NONBLOCK in the open, and the read does not return _immediately_ unless I use a SIGALRM. I have also added the fcntl call, with the same results. if(fcntl(fd, F_SETSIG, O_NONBLOCK) < 0) { fprintf(stderr, "error fcntl:%d - %s\n", errno, strerror(errno)); return(-1); } Is that a typo for fcntl(fd, F_SETFL, O_NONBLOCK)? Try this after open... int fdflags = fcntl(fd, F_GETFL); if (fdflags == -1) { perror("GETFL"); exit(1); } if (!(fdflags & O_NONBLOCK)) { fprintf(stderr, "O_NONBLOCK not set even though we asked for it\n"); exit(1); } Then strace your test program and show me the output of strace. You do mean the _read_ doesn't return immediately, don't you? Not just that your my_get_com_byte() function doesn't return immediately? What changes did you make to your function? As shown above, it'd just sit in an tight loop calling read() over and over again until the alarm happens... Yes, that is why I need to know how many bytes are on the port. So I don't have to wait for the 1 second time out and I can do an intelligent read for nchar. The code would then look like this. if((i = ioctl( fd, FIONREAD, &nchar )) == -1) return(-1); for(i = 1; i <= nchar; i++) { .... } if you have O_NONBLOCK set you can just do ret = read(fd, buf, BUFFERSPACELEFT); that will return 0 if there are no characters pending, and the amount read if there's > 1. no need to loop no need for the IOCTL To clarify.... where you seem to want a function which reads all currently-available characters (up to the buffer size 'max') from the serial port, which would look like the following: int read_serial_port(int fd, char *buf, int max) { int nchar; if (ioctl(fd, FIONREAD, &nchar) == -1) return -1; if (nchar > max) nchar = max; return read(fd, buf, nchar); } .... it can in fact be done with O_NONBLOCK as follows: int read_serial_port(int fd, char *buf, int max) { return read(fd, buf, max); } Here is the strace output. Do you want see all the strace output or just the open? open("/dev/ttyS0", O_RDWR|O_NONBLOCK) = 3 fcntl64(3, F_GETFL) = 0x802 (flags O_RDWR|O_NONBLOCK) write(3, "0123456789", 10) = 10 fstat64(1, {st_mode=S_IFCHR|0600, st_rdev=makedev(136, 1), ...}) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb75ea000 write(1, "\n", 1) = 1 write(1, "Write 10 bytes \n", 16) = 16 ioctl(3, FIONREAD, [0]) = 0 write(1, "Found 0 0 bytes in port buffer\n", 31) = 31 rt_sigaction(SIGALRM, {0x8048ab2, [ALRM], SA_RESTORER|SA_RESTART, 0xb72b0b78}, {SIG_DFL}, 8) = 0 alarm(1) = 0 ioctl(3, FIONREAD, [0]) = 0 write(1, "Found 0 0 bytes in port buffer\n", 31) = 31 r All of it please. You haven't shown read() blocking. I don't believe read() blocks when the O_NONBLOCK flag is set.... I believe your function is calling read() over and over again in a tight loop. Thanks for the help, it looks like the select and O_NONBLOCK is going to give us what we need for now for our serail io processing. Is someone could look into why FIONREAD does not return the number of bytes on the port it would be helpful to us in the future. This test program shows FIONREAD (which is also known as TIOCINQ) working correctly; run it and see its output when there are data available on the port... FIONREAD says 0 chars available FIONREAD says 0 chars available FIONREAD says 0 chars available FIONREAD says 7 chars available FIONREAD says 7 chars available FIONREAD says 7 chars available I suspect your calls to FIONREAD in your test program were happening before the kernel had registered that there were data available. #include <sys/ioctl.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> int main(void) { int fd, nchar; fd = open("/dev/ttyS0", O_RDWR); if (fd == -1) { perror("open"); exit(1); } while(1) { if (ioctl(fd, FIONREAD, &nchar)) { perror("ioctl(FIONREAD)"); exit(1); } printf("FIONREAD says %d chars available\n", nchar); sleep(1); } return 0; } Indeed.... if you put the FIONREAD ioctl into the loop in my_get_com_byte() in your original test case, you'll see it returning a non-zero number of characters. |