summaryrefslogtreecommitdiff
path: root/libgpsd_core.c
diff options
context:
space:
mode:
authorEric S. Raymond <esr@thyrsus.com>2010-04-07 08:37:57 -0400
committerEric S. Raymond <esr@thyrsus.com>2010-04-07 08:37:57 -0400
commit0ee8c304ad8466d0e656e50c29692b0302fcbd9c (patch)
tree5f68d351430159a18f0992c885e08e368bd659c7 /libgpsd_core.c
parenta0f13cb50324d587303402a6ac2713258f056177 (diff)
downloadgpsd-0ee8c304ad8466d0e656e50c29692b0302fcbd9c.tar.gz
Fix the select()-spin bug on disconnected devices.
Addresses Berlios tracker bug #14638: 100% cpu when Bluetooth gps device vanishes. Also a couple of reports on the mailing lists. The underlying problem here was that: * Disconnecting a USB device causes reads from it to begin returning 0, in effect an end-of-file condition. * select(2) sets an active bit not on "I/O is ready" but on "read would not block" -- including the end-of-file condition. * Therefore, select() will spin any time its fd set includes a disconnected device. The fix is to check for a zero-length read explicitly and always take the device out of the active set when that happens. We were actually doing that here, but the test was defective in two ways: 1. The check for a zero return from gpsd_poll(), indicating I/O error or zero-length read, needed to be *before* the check for full paccket rather than after. This effectively disabled it. 2. There was a conditional arm in the gpsd_poll() code that made it ignore zero-length reads for up to a full cycle. I think this may have been a fossil from long ago when I experimented with non-blocking reads on devices. The fix for the gpsmon spin bug is probably quite similar. That's up next.
Diffstat (limited to 'libgpsd_core.c')
-rw-r--r--libgpsd_core.c17
1 files changed, 4 insertions, 13 deletions
diff --git a/libgpsd_core.c b/libgpsd_core.c
index 533ea907..72c637ea 100644
--- a/libgpsd_core.c
+++ b/libgpsd_core.c
@@ -621,21 +621,12 @@ gps_mask_t gpsd_poll(struct gps_device_t *session)
/* update the scoreboard structure from the GPS */
gpsd_report(LOG_RAW+2, "%s sent %zd new characters\n",
session->gpsdata.dev.path, newlen);
- if (newlen == -1) { /* read error */
- gpsd_report(LOG_INF, "GPS on %s is offline (%lf sec since data)\n",
- session->gpsdata.dev.path,
- timestamp() - session->gpsdata.online);
+ if (newlen <= 0) { /* read error or EOF*/
+ gpsd_report(LOG_INF, "GPS on %s is offline (%lf sec since data)\n",
+ session->gpsdata.dev.path,
+ timestamp() - session->gpsdata.online);
session->gpsdata.online = 0;
return 0;
- } else if (newlen == 0) { /* no new data */
- if (session->device_type != NULL && timestamp()>session->gpsdata.online+session->gpsdata.dev.cycle+1) {
- gpsd_report(LOG_INF, "GPS on %s is offline (%lf sec since data)\n",
- session->gpsdata.dev.path,
- timestamp() - session->gpsdata.online);
- session->gpsdata.online = 0;
- return 0;
- } else
- return ONLINE_SET;
} else if (session->packet.outbuflen == 0) { /* got new data, but no packet */
gpsd_report(LOG_RAW+3, "New data on %s, not yet a packet\n",
session->gpsdata.dev.path);