summaryrefslogtreecommitdiff
path: root/serial.c
diff options
context:
space:
mode:
authorEric S. Raymond <esr@thyrsus.com>2015-01-31 15:16:55 -0500
committerEric S. Raymond <esr@thyrsus.com>2015-01-31 15:16:55 -0500
commit6ee9556f2fea231303a488f07a8b0e0a9f552dc4 (patch)
tree0427b34e9b53f0317b3c575ef5cd507bae92be35 /serial.c
parent2bab8b2a7f810a4a430def430cbae80d74c572c6 (diff)
downloadgpsd-6ee9556f2fea231303a488f07a8b0e0a9f552dc4.tar.gz
Back out the attempt to use VTIME.
According to Matthias Drochner at http://lists.lysator.liu.se/pipermail/lsh-bugs/2003q4/000151.html: I thought I'd give lsh a try, just to see how it compares to openssh... The client didn't work well on NetBSD, got a message like "unexpected EWOULDBLOCK" on each keystroke. Looked a bit deeper and found that stdin is set to O_NONBLOCK and a raw tty mode with c_cc[VMIN] > 1 and c_cc[VTIME] > 0. I'll append a little test program which does the same. I've tried it on 3 operating systems (Linux, NetBSD, Digital UNIX), and it behaves differently on each: -on Linux, if a key is pressed, the read returns immediately with that one character -on NetBSD, the read returns with no data but EWOULDBLOCK -on D'UNIX, the poll() doesn't teturn before 4 keypresses are done; the read() returns these 4 characters Indeed, in SUSv2's termios page is a sentence which says that if both O_NONBLOCK and VTIME>0 are set, the behaviour is more or less undefined. I've solved my immediate problems by setting VMIN to 1 instead of 4 in unix_interact.c:do_make_raw(), but VTIME is still pointless, so I wouldn't call this a clean solution. All regression tests pass.
Diffstat (limited to 'serial.c')
-rw-r--r--serial.c69
1 files changed, 13 insertions, 56 deletions
diff --git a/serial.c b/serial.c
index 25333678..9bc74e13 100644
--- a/serial.c
+++ b/serial.c
@@ -535,7 +535,19 @@ int gpsd_serial_open(struct gps_device_t *session)
&session->ttyset_old, sizeof(session->ttyset));
/*
* Only block until we get at least one character, whatever the
- * third arg of read(2) says.
+ * third arg of read(2) says. According to
+ * http://stackoverflow.com/questions/20154157/termios-vmin-vtime-and-blocking-non-blocking-read-operations
+ * the VMIN setting may be a no-op because the tty was opened with
+ * O_NONBLOCK. Money quote:
+ *
+ * "When using select() with a file in non-blocking mode, you
+ * get an event for every byte that arrives. At high serial
+ * data rates, this hammers the CPU. It's better to use
+ * blocking mode with VMIN, so that select() waits for a
+ * block of data before firing an event, and VTIME to limit
+ * the delay, for blocks smaller than VMIN."
+ *
+ * Would that we could do the latter...
*/
/*@ ignore @*/
memset(session->ttyset.c_cc, 0, sizeof(session->ttyset.c_cc));
@@ -609,61 +621,6 @@ ssize_t gpsd_serial_write(struct gps_device_t * session,
return status;
}
-void gpsd_optimize_io(struct gps_device_t *session,
- int minlength, const bool textual UNUSED)
-/* optimize I/O mode depending on the minimum packet size */
-{
- /* bail out if this is not actually a tty */
- if (isatty(session->gpsdata.gps_fd) == 0)
- return;
-
-#ifdef __NetBSD__
- /*
- * Apparently NetBSD termios (at least on pty on netbsd-[56]) has
- * trouble with VMIN=n VTIME=1. Or reads are aftempted when no
- * bytes are present and none arrive, in which case read is
- * correct for waiting indefinitely. Until this is
- * debugged/fixed, avoid it, because even if it doesn't affect
- * actual operation (unknown) it's important to preserve
- * regression tests to allow bisecting for other bugs.
- * http://pubs.opengroup.org/onlinepubs/007908799/xbd/termios.html
- */
- minlength = 1;
-#endif
-
- /*
- * This is an optimization hack. The idea is to get away from
- * character-at-a-time I/O in order to slow down the rate at
- * which the main select loop spins (those calls eat power
- * noticeably in environments like Android phones and the
- * Raspberry Pi). We tell the tty layer to wait until it has
- * either accumulated characters corresponding to the minimum
- * possible length of a packet or timed out.
- *
- * For the moment, we do nothing with the textual flag. We'd like
- * to use it to set ICANON mode and let the kernel do all the line
- * buffering itself. The problem with this is that VTIME stops
- * working in ICANON mode, so a binary packet coming up the wire
- * would result in no further input being seen.
- */
- if (minlength > 1) {
- session->ttyset.c_cc[VMIN] = minlength;
- session->ttyset.c_cc[VTIME] = 1; /* 0.1 sec */
- } else {
- /* raw character-at-at-time I/O, no timeout */
- session->ttyset.c_cc[VMIN] = 1;
- session->ttyset.c_cc[VTIME] = 0;
- }
-
- if (tcsetattr(session->gpsdata.gps_fd, TCSANOW, &session->ttyset) != 0)
- return;
-
- gpsd_report(&session->context->errout, LOG_IO,
- "tty params optimized for min length %d of %s packets\n",
- minlength, textual ? "textual" : "binary");
-}
-
-
/*
* This constant controls how long the packet sniffer will spend looking
* for a packet leader before it gives up. It *must* be larger than