summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am1
-rw-r--r--configure.ac40
-rw-r--r--gps.h4
-rw-r--r--gpsd.c18
-rw-r--r--gpsd.h-tail17
-rw-r--r--libgpsd_core.c3
-rw-r--r--shmexport.c79
7 files changed, 148 insertions, 14 deletions
diff --git a/Makefile.am b/Makefile.am
index 9f5fa08d..2484c1e2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -182,6 +182,7 @@ libgpsd_c_sources = \
packet.c \
pseudonmea.c \
serial.c \
+ shmexport.c \
srecord.c \
subframe.c \
drivers.c \
diff --git a/configure.ac b/configure.ac
index 7c540922..9ba3705c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -570,19 +570,6 @@ fi
AM_CONDITIONAL([CLIENTDEBUG_ENABLE], [test x"$ac_clientdebug" = x"yes"])
-dnl check for socket export support
-AC_ARG_ENABLE(socket_export,
- AC_HELP_STRING([--disable-socket-export],
- [disable data export over sockets]),
- [ac_socket_export=$enableval], [ac_socket_export=yes])
-AC_MSG_CHECKING([for socket-export support])
-if test x"$ac_socket_export" = "xyes"; then
- AC_MSG_RESULT([yes])
- AC_DEFINE([SOCKET_EXPORT_ENABLE], 1, [socket-export support])
-else
- AC_MSG_RESULT([no])
-fi
-
dnl check for support for oldstyle protocol
AC_ARG_ENABLE(oldstyle,
AC_HELP_STRING([--disable-oldstyle],
@@ -710,7 +697,18 @@ else
AC_MSG_RESULT([no])
fi
-
+dnl check for socket export support
+AC_ARG_ENABLE(socket-export,
+ AC_HELP_STRING([--disable-socket-export],
+ [disable data export over sockets]),
+ [ac_socket_export=$enableval], [ac_socket_export=yes])
+AC_MSG_CHECKING([for socket-export support])
+if test x"$ac_socket_export" = "xyes"; then
+ AC_MSG_RESULT([yes])
+ AC_DEFINE([SOCKET_EXPORT_ENABLE], 1, [socket-export support])
+else
+ AC_MSG_RESULT([no])
+fi
dnl Manually configure DBUS until we figure out a
dnl distro-independent was to check for both libraries and headers
@@ -736,6 +734,19 @@ else
AC_MSG_RESULT([no])
fi
+dnl check for shm export support
+AC_ARG_ENABLE(shm-export,
+ AC_HELP_STRING([--enable-shm-export],
+ [enable export via shared memory]),
+ [ac_shm_export=$enableval], [ac_shm_export=no])
+AC_MSG_CHECKING([for shared-memory-export support])
+if test x"$ac_shm_export" == "xyes"; then
+ AC_MSG_RESULT([yes])
+ AC_DEFINE([SHM_EXPORT_ENABLE], 1, [shared-memory-export support])
+else
+ AC_MSG_RESULT([no])
+fi
+
dnl check for limited maximum clients
AC_ARG_ENABLE(max-clients,
AC_HELP_STRING([--enable-max-clients=nnn],
@@ -1004,6 +1015,7 @@ dnl Below this line are non-protocol switches
echo " Daemon Features"
echo " ---------------"
echo "Socket export : $ac_socket_export"
+echo "Shared-memory export : $ac_shm_export"
echo "DBUS export : $ac_dbus_export"
echo "Timing support : $ac_timing"
echo "NTP SHM : $ac_ntpshm"
diff --git a/gps.h b/gps.h
index 34a24e4a..7f31e787 100644
--- a/gps.h
+++ b/gps.h
@@ -1437,6 +1437,10 @@ extern int gps_stream(struct gps_data_t *, unsigned int, /*@null@*/void *);
extern const char /*@observer@*/ *gps_data(struct gps_data_t *);
extern const char /*@observer@*/ *gps_errstr(const int);
+extern int gps_shm_open(/*@out@*/struct gps_data_t *);
+extern int gps_shm_read(/*@out@*/struct gps_data_t *);
+extern int gps_shm_close(struct gps_data_t *);
+
/* this only needs to be visible for the unit tests */
extern int gps_unpack(char *, struct gps_data_t *);
diff --git a/gpsd.c b/gpsd.c
index f494dee9..c9cb79b6 100644
--- a/gpsd.c
+++ b/gpsd.c
@@ -1507,6 +1507,12 @@ static void consume_packets(struct gps_device_t *device)
#endif /* DBUS_EXPORT_ENABLE */
}
+#ifdef SHM_EXPORT_ENABLE
+ if ((changed & (REPORT_IS|NOISE_IS|SATELLITE_IS|SUBFRAME_IS|
+ ATT_IS|RTCM2_IS|RTCM3_IS|AIS_IS)) != 0)
+ shm_update(&context, &device->gpsdata);
+#endif /* DBUS_EXPORT_ENABLE */
+
#ifdef SOCKET_EXPORT_ENABLE
/* update all subscribers associated with this device */
for (sub = subscribers; sub < subscribers + MAXSUBSCRIBERS; sub++) {
@@ -1854,6 +1860,14 @@ int main(int argc, char *argv[])
"successfully connected to the DBUS system bus\n");
#endif /* DBUS_EXPORT_ENABLE */
+#ifdef SHM_EXPORT_ENABLE
+ /* create the shared segment as root so readers can't mess with it */
+ if (!shm_acquire(&context)) {
+ gpsd_report(LOG_ERROR, "shared-segment creation failed,\n");
+ } else
+ gpsd_report(LOG_PROG, "shared-segment creation succeeded,\n");
+#endif /* DBUS_EXPORT_ENABLE */
+
if (getuid() == 0 && go_background) {
struct passwd *pw;
struct stat stb;
@@ -2223,6 +2237,10 @@ int main(int argc, char *argv[])
}
#endif /* SOCKET_EXPORT_ENABLE */
+#ifdef SHM_EXPORT_ENABLE
+ shm_release(&context);
+#endif /* DBUS_EXPORT_ENABLE */
+
if (control_socket)
(void)unlink(control_socket);
if (pid_file)
diff --git a/gpsd.h-tail b/gpsd.h-tail
index 026bc617..f8f46b19 100644
--- a/gpsd.h-tail
+++ b/gpsd.h-tail
@@ -207,6 +207,11 @@ struct gps_context_t {
bool shmTimePPS;
# endif /* PPS_ENABLE */
#endif /* NTPSHM_ENABLE */
+#ifdef SHM_EXPORT_ENABLE
+ /* we don't want the compiler to treat writes to shmexport as dead code,
+ * and we don't want them reordered either */
+ /*@reldef@*/volatile char *shmexport;
+#endif
};
struct aivdm_context_t {
@@ -705,6 +710,18 @@ extern void ecef_to_wgs84fix(/*@out@*/struct gps_fix_t *,
double, double, double);
extern void clear_dop(/*@out@*/struct dop_t *);
+/* shmexport.c */
+#define GPSD_KEY 0x47505344 /* "GPSD" */
+struct shmexport_t
+{
+ int bookend1;
+ struct gps_data_t gpsdata;
+ int bookend2;
+};
+extern bool shm_acquire(struct gps_context_t *);
+extern void shm_release(struct gps_context_t *);
+extern void shm_update(struct gps_context_t *, struct gps_data_t *);
+
/* srecord.c */
extern void hexdump(size_t, unsigned char *, unsigned char *);
extern unsigned char sr_sum(unsigned int, unsigned int, unsigned char *);
diff --git a/libgpsd_core.c b/libgpsd_core.c
index 05757b17..a4bc9815 100644
--- a/libgpsd_core.c
+++ b/libgpsd_core.c
@@ -105,6 +105,9 @@ void gps_context_init(struct gps_context_t *context)
.shmTimePPS = false,
# endif /* PPS_ENABLE */
#endif /* NTPSHM_ENABLE */
+#ifdef SHM_EXPORT_ENABLE
+ .shmexport = NULL,
+#endif /* SHM_EXPORT_ENABLE */
};
/*@ +initallelements +nullassign +nullderef @*/
/* *INDENT-ON* */
diff --git a/shmexport.c b/shmexport.c
new file mode 100644
index 00000000..b9c330c4
--- /dev/null
+++ b/shmexport.c
@@ -0,0 +1,79 @@
+/****************************************************************************
+
+NAME
+ shmexport.c - shared-memory exports from the daemon and how to read them
+
+DESCRIPTION
+
+
+PERMISSIONS
+ This file is Copyright (c) 2010 by the GPSD project
+ BSD terms apply: see the file COPYING in the distribution root for details.
+
+***************************************************************************/
+#include <stddef.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+#include "gpsd.h"
+
+#ifdef SHM_EXPORT_ENABLE
+bool shm_acquire(struct gps_context_t *context)
+/* initialize the shared-memory segment to be used for export */
+{
+ int shmid;
+
+ shmid = shmget((key_t)GPSD_KEY, sizeof(struct gps_data_t), (int)(IPC_CREAT|0666));
+ if (shmid == -1) {
+ gpsd_report(LOG_ERROR, "shmget(%ld, %zd, 0666) failed: %s\n",
+ (long int)GPSD_KEY,
+ sizeof(struct gps_data_t),
+ strerror(errno));
+ return false;
+ }
+ context->shmexport = (char *)shmat(shmid, 0, 0);
+ /*@ -mustfreefresh */
+ if ((int)(long)context->shmexport == -1) {
+ gpsd_report(LOG_ERROR, "shmat failed: %s\n", strerror(errno));
+ context->shmexport = NULL;
+ return false;
+ }
+ gpsd_report(LOG_PROG, "shmat() succeeded, segment %d\n", shmid);
+ return true;
+}
+
+void shm_release(struct gps_context_t *context)
+/* release the shared-memory segment used for export */
+{
+ if (context->shmexport != NULL)
+ (void)shmdt((const void *)context->shmexport);
+}
+
+void shm_update(struct gps_context_t *context, struct gps_data_t *gpsdata)
+/* export an update to all listeners */
+{
+ if (context->shmexport != NULL)
+ {
+ static int tick;
+
+ ++tick;
+ /*
+ * Following block of instructions must not be reordered, otherwise
+ * havoc will ensue. asm volatile("sfence") is a GCCism intended
+ * to prevent reordering.
+ */
+ ((struct shmexport_t *)context)->bookend2 = tick;
+ asm volatile("sfence");
+ memcpy((void *)(context->shmexport + offsetof(struct shmexport_t, gpsdata)),
+ (void *)gpsdata,
+ sizeof(struct gps_data_t));
+ asm volatile("sfence");
+ ((struct shmexport_t *)context)->bookend1 = tick;
+ }
+}
+#endif /* SHM_EXPORT_ENABLE */
+
+/* end */