summaryrefslogtreecommitdiffstats
path: root/refclock_shm.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--refclock_shm.c136
1 files changed, 136 insertions, 0 deletions
diff --git a/refclock_shm.c b/refclock_shm.c
new file mode 100644
index 0000000..ed68095
--- /dev/null
+++ b/refclock_shm.c
@@ -0,0 +1,136 @@
+/*
+ chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar 2009
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ **********************************************************************
+
+ =======================================================================
+
+ SHM refclock driver.
+
+ */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "refclock.h"
+#include "logging.h"
+#include "util.h"
+
+#define SHMKEY 0x4e545030
+
+struct shmTime {
+ int mode; /* 0 - if valid set
+ * use values,
+ * clear valid
+ * 1 - if valid set
+ * if count before and after read of values is equal,
+ * use values
+ * clear valid
+ */
+ volatile int count;
+ time_t clockTimeStampSec;
+ int clockTimeStampUSec;
+ time_t receiveTimeStampSec;
+ int receiveTimeStampUSec;
+ int leap;
+ int precision;
+ int nsamples;
+ volatile int valid;
+ int clockTimeStampNSec;
+ int receiveTimeStampNSec;
+ int dummy[8];
+};
+
+static int shm_initialise(RCL_Instance instance) {
+ const char *options[] = {"perm", NULL};
+ int id, param, perm;
+ char *s;
+ struct shmTime *shm;
+
+ RCL_CheckDriverOptions(instance, options);
+
+ param = atoi(RCL_GetDriverParameter(instance));
+ s = RCL_GetDriverOption(instance, "perm");
+ perm = s ? strtol(s, NULL, 8) & 0777 : 0600;
+
+ id = shmget(SHMKEY + param, sizeof (struct shmTime), IPC_CREAT | perm);
+ if (id == -1) {
+ LOG_FATAL("shmget() failed : %s", strerror(errno));
+ return 0;
+ }
+
+ shm = (struct shmTime *)shmat(id, 0, 0);
+ if ((long)shm == -1) {
+ LOG_FATAL("shmat() failed : %s", strerror(errno));
+ return 0;
+ }
+
+ RCL_SetDriverData(instance, shm);
+ return 1;
+}
+
+static void shm_finalise(RCL_Instance instance)
+{
+ shmdt(RCL_GetDriverData(instance));
+}
+
+static int shm_poll(RCL_Instance instance)
+{
+ struct timespec receive_ts, clock_ts;
+ struct shmTime t, *shm;
+ double offset;
+
+ shm = (struct shmTime *)RCL_GetDriverData(instance);
+
+ t = *shm;
+
+ if ((t.mode == 1 && t.count != shm->count) ||
+ !(t.mode == 0 || t.mode == 1) || !t.valid) {
+ DEBUG_LOG("SHM sample ignored mode=%d count=%d valid=%d",
+ t.mode, t.count, t.valid);
+ return 0;
+ }
+
+ shm->valid = 0;
+
+ receive_ts.tv_sec = t.receiveTimeStampSec;
+ clock_ts.tv_sec = t.clockTimeStampSec;
+
+ if (t.clockTimeStampNSec / 1000 == t.clockTimeStampUSec &&
+ t.receiveTimeStampNSec / 1000 == t.receiveTimeStampUSec) {
+ receive_ts.tv_nsec = t.receiveTimeStampNSec;
+ clock_ts.tv_nsec = t.clockTimeStampNSec;
+ } else {
+ receive_ts.tv_nsec = 1000 * t.receiveTimeStampUSec;
+ clock_ts.tv_nsec = 1000 * t.clockTimeStampUSec;
+ }
+
+ UTI_NormaliseTimespec(&clock_ts);
+ UTI_NormaliseTimespec(&receive_ts);
+ offset = UTI_DiffTimespecsToDouble(&clock_ts, &receive_ts);
+
+ return RCL_AddSample(instance, &receive_ts, offset, t.leap);
+}
+
+RefclockDriver RCL_SHM_driver = {
+ shm_initialise,
+ shm_finalise,
+ shm_poll
+};