One major design decision made by the GPSD team is that there should be no memory allocation functions."Don't Use Malloc" is one of the bullet points in the contribution guidelines (http://gpsd.berlios.de/hacking.html#malloc).
The best way to avoid having dynamic-memory allocation problems is not to use malloc/free at all. The gpsd daemon doesn't (though the client-side code does). Thus, even the longest-running instance can't have memory leaks. The only cost for this turned out to be embedding a PATH_MAX-sized buffer in the gpsd.h structure.This cost analysis is not quite true. It means that all arrays must be preallocated even if the memory is not used for the program at all. There was, at one point, an array of 1024 device structures which allowed for 1024 devices to be connected. This whole array was allocated even if there was only one device (which is a more common case than 1024). Each structure was 20K, which meant there was about 14meg wasted. Recent versions of gpsd have reduced this count to only 4 structures, which is only a waste of 60k or so in the common case. While this isn't such a terrible waste any more, it is still a bandaid over the problem rather than a solution. Rather having a sensible memory allocation strategy would make the code less complicated and mean that there was no wasted memory at all.Don't undo this by using malloc/free in a driver or anywhere else.
GPSD is designed around the idea that it can be accessed remotely. It sets itself up as a server on port 2947. By default, as of recent versions, the behaviour is only to allow connections from the local machine, but the functionality is still there if needed and local connections are treated the same as remote connections.
The problem is I have a hard time coming up with use cases for this in either general use cases for GPS devices, or the use cases GPSD was designed for (http://gpsd.berlios.de/hacking.html#audience). But because of this useless feature (which is turned off by default) the common use case is made more complicated because of the primitive IPC that GPSD needs to use to support it.
GPSD was written originally in 1995, back then there were few options for sane IPC (CORBA being rather heavyweight) and using TCPIP sockets might have been the best option. However, nearly 15 years later, we have a very successful IPC protocol in D-Bus which provides the things that GPSD's string and socket based protocol lacks such as type safety.
GPSD works that your client opens a socket to the server and sends it a command. The commands are currently all letters, although at the time of writing there is only one letter left unused and so a new format is being discussed. GPSD replies to every letter with a string. Each parameter in the string is separated by (what appears to be a random number of) spaces. The Y command is separated by spaces, except for the quads which are separated by commas.
These inconsistencies make it awkward to parse by hand and although GPSD supplies libgps which handles this for you, as we shall see, it has issues of its own which make it, in my opinion, a less optimal solution. The proposed version of the GPSD message protocol currently allows for multiple letter commands and for multiple line responses. This again adds to the complexity of parsing, which is all something that a proper IPC system such as D-Bus provides.
GPSD provides a client library called libgps which simplifies writing client programs that interface with the daemon. This library handles all the parsing of the GPSD replies and passes the client a structure with the values filled in.
There is both a push and a pull method of accessing the GPS data. In both methods the user sets a callback function. The push method is done via threads and the callback is called in a separate thread whenever the data is received from GPSD. In the pull method, the client calls gps_poll and the program blocks until data is available. When data is available the callback is called and the program continues.
The first problem is that the options for a programmer are either blocking or threads. This is fine for a non-interactive console program, but for GUI programmers blocking calls are a big no no. Every blocking call potentially freezes the UI. On the other hand in many GUI toolkits using threads is awkward and no GUI operations may happen from a secondary thread. Again this complicates the programs using the API.
The second problem with the API as it stands is that there is no way to pass data to the callback meaning that any data needed by the callback must be a global variable. Again in a simple non-interactive console program global variables are not too big a deal, but for a GUI program they are frowned upon.
Thirdly the API has no concept of objects. Only one callback can be registered for each of the methods (one for the thread method, and one for the poll method).This again means that the one callback has to do everything that needs to be done in the program related to GPS functions. While again it is possible, it complicates object oriented programs and breaks the encapsulation of data.
GPSD is designed to be run at system start, and stopped when the system is shutdown (or for USB/bluetooth hotplug devices started when that device is plugged in or removed). If a client is started before GPSD is running (for example a GPS applet is started before the BT device is connected), then the only way for it to know that GPSD is for it to attempt to connect to the GPSD socket and keep trying every so often until it succeeds. This makes gpsd client programs very busy, always having to wake up to check to see if it can connect and on a system that runs on batteries having processes that can't sleep very often is a bad thing that drains away the battery.
Because GPSD is designed to always be running and always report fix data, there is no provision for turning it on and off, except by killing the process. For systems that try to minimise processor usage while the device is idle, this makes it hard for programs, as they have to either be listening to GPSD emitting data, or trying to connect to the socket to see if GPSD has started up again.
Also with regards to clients being woken up, even when GPSD is running clients get notified about everything, even if they don't care about it. GPSD emits a new fix on every NMEA sentence received, which for most GPS devices is about 5 a second and each time the clients are all woken up even if they don't care about the data that has changed. GPSD has no way for clients to say that they are only interested in position data, or only in whether the device has a fix or not. Even if the GPS unit is stationary, satellite data is constantly changing, and the clients will be woken up on every message.
Finally, and this may seem like a picky point, but the code is filled with comments that lint can check its perfectness. The problem, to me, is that all this just clutters the code and makes it harder to read and understand, but like I said, this is just a personal thing.
Gypsy also provides finer grained signals. There are currently five different signals that a client can listen for:
Even though the GPS device is constantly sending Gypsy data, Gypsy checks whether or not the data has changed before emitting a signal. So if, for example, the device is stationary, no PositionChanged signals will be emitted until the device starts to move again, once more allowing programs to sleep more often.
Using D-Bus allows the API to be combined with main loops using the D-Bus object bindings. Gypsy comes with libgypsy which is a GObject binding for the D-Bus protocol allowing Gypsy to be used in a GObject based system such as Gtk+ or GNOME. Other object bindings could be written to integrate Gypsy with QT and KDE for example.
Hopefully with Gypsy, we can great a much more powerful location-aware system for modern desktops.