[chrony-dev] [PATCH] Support multiple extpps refclocks on a single PHC device

[ Thread Index | Date Index | More chrony.tuxfamily.org/chrony-dev Archives ]


On Linux, an extpps pin on a PHC device firing will only be read
once. If there are multiple sockets to that PHC device (even across
channels), the event will only be read by the first reader to get
to the kernel.

This poses a problem for chrony - if we have two PHC extpps
refclocks both reading from the same device, we'll only get a
sample if the refclock listening on the right channel happens to be
the one that gets the sample. To avoid this, we have to queue up
samples with a mismatched channel, which we do here in a simple
static buffer, scanning for missed samples when the PHC driver is
polled.
---
 refclock_phc.c | 78 ++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 70 insertions(+), 8 deletions(-)

diff --git a/refclock_phc.c b/refclock_phc.c
index e0e206e..10b942d 100644
--- a/refclock_phc.c
+++ b/refclock_phc.c
@@ -42,6 +42,19 @@
 #include "sched.h"
 #include "sys_linux.h"

+#include <pthread.h>
+struct phc_unknown_channel_data {
+  char valid;
+  int channel;
+  const char *path;
+  struct timespec phc_ts;
+};
+
+#define UNKNOWN_CHAN_BUF_SZ 32
+static struct phc_unknown_channel_data unknown_chan_buf[UNKNOWN_CHAN_BUF_SZ];
+static pthread_mutex_t unknown_chan_buf_mtx = PTHREAD_MUTEX_INITIALIZER;
+static char unknown_chan_buf_initd = 0;
+
 struct phc_instance {
   int fd;
   int mode;
@@ -49,6 +62,7 @@ struct phc_instance {
   int extpps;
   int pin;
   int channel;
+  char *path;
   HCL_Instance clock;
 };

@@ -75,6 +89,9 @@ static int phc_initialise(RCL_Instance instance)
   phc->nocrossts = RCL_GetDriverOption(instance, "nocrossts") ? 1 : 0;
   phc->extpps = RCL_GetDriverOption(instance, "extpps") ? 1 : 0;

+  phc->path = Malloc(strlen(path));
+  strcpy(phc->path, path);
+
   phc->clock = HCL_CreateInstance(0, 16, UTI_Log2ToDouble(RCL_GetDriverPoll(instance)),
                                   RCL_GetPrecision(instance));

@@ -109,17 +126,40 @@ static void phc_finalise(RCL_Instance instance)
     SYS_Linux_SetPHCExtTimestamping(phc->fd, phc->pin, phc->channel, 0, 0, 0);
   }

+  pthread_mutex_lock(&unknown_chan_buf_mtx);
+  for (int i = 0; i < UNKNOWN_CHAN_BUF_SZ; i++) {
+    if (unknown_chan_buf[i].path == phc->path) {
+      unknown_chan_buf[i].valid = 0;
+    }
+  }
+  pthread_mutex_unlock(&unknown_chan_buf_mtx);
+
   HCL_DestroyInstance(phc->clock);
   close(phc->fd);
+  Free(phc->path);
   Free(phc);
 }

+static void handle_ext_pulse(RCL_Instance instance, struct timespec phc_ts)
+{
+  struct phc_instance *phc;
+  struct timespec local_ts;
+  double local_err;
+
+  phc = RCL_GetDriverData(instance);
+
+  if (!HCL_CookTime(phc->clock, &phc_ts, &local_ts, &local_err))
+    return;
+
+  RCL_AddCookedPulse(instance, &local_ts, 1.0e-9 * local_ts.tv_nsec, local_err,
+                     UTI_DiffTimespecsToDouble(&phc_ts, &local_ts));
+}
+
 static void read_ext_pulse(int fd, int event, void *anything)
 {
   RCL_Instance instance;
   struct phc_instance *phc;
-  struct timespec phc_ts, local_ts;
-  double local_err;
+  struct timespec phc_ts;
   int channel;

   instance = anything;
@@ -130,14 +170,23 @@ static void read_ext_pulse(int fd, int event, void *anything)

   if (channel != phc->channel) {
     DEBUG_LOG("Unexpected extts channel %d\n", channel);
+    pthread_mutex_lock(&unknown_chan_buf_mtx);
+    if (!unknown_chan_buf_initd) {
+      for (int i = 0; i < UNKNOWN_CHAN_BUF_SZ; i++) unknown_chan_buf[i].valid = 0;
+      unknown_chan_buf_initd = 1;
+    }
+    int wrpos = phc_ts.tv_nsec % UNKNOWN_CHAN_BUF_SZ;
+    for (int i = 0; i < UNKNOWN_CHAN_BUF_SZ; i++) {
+      if (!unknown_chan_buf[i].valid) wrpos = i;
+    }
+    unknown_chan_buf[wrpos].channel = channel;
+    unknown_chan_buf[wrpos].path = phc->path;
+    unknown_chan_buf[wrpos].phc_ts = phc_ts;
+    unknown_chan_buf[wrpos].valid = 1;
+    pthread_mutex_unlock(&unknown_chan_buf_mtx);
     return;
   }
-
-  if (!HCL_CookTime(phc->clock, &phc_ts, &local_ts, &local_err))
-    return;
-
-  RCL_AddCookedPulse(instance, &local_ts, 1.0e-9 * local_ts.tv_nsec, local_err,
-                     UTI_DiffTimespecsToDouble(&phc_ts, &local_ts));
+  handle_ext_pulse(instance, phc_ts);
 }

 #define PHC_READINGS 25
@@ -162,6 +211,19 @@ static int phc_poll(RCL_Instance instance)
   LCL_CookTime(&sys_ts, &local_ts, &local_err);
   HCL_AccumulateSample(phc->clock, &phc_ts, &local_ts, phc_err + local_err);

+  pthread_mutex_lock(&unknown_chan_buf_mtx);
+  if (!unknown_chan_buf_initd) {
+    for (int i = 0; i < UNKNOWN_CHAN_BUF_SZ; i++) unknown_chan_buf[i].valid = 0;
+    unknown_chan_buf_initd = 1;
+  }
+  for (int i = 0; i < UNKNOWN_CHAN_BUF_SZ; i++) {
+    if (!unknown_chan_buf[i].valid) continue;
+    if (unknown_chan_buf[i].channel != phc->channel) continue;
+    if (strcmp(unknown_chan_buf[i].path, phc->path)) continue;
+    handle_ext_pulse(instance, unknown_chan_buf[i].phc_ts);
+  }
+  pthread_mutex_unlock(&unknown_chan_buf_mtx);
+
   if (phc->extpps)
     return 0;

--
2.39.1

--
To unsubscribe email chrony-dev-request@xxxxxxxxxxxxxxxxxxxx with "unsubscribe" in the subject.
For help email chrony-dev-request@xxxxxxxxxxxxxxxxxxxx with "help" in the subject.
Trouble?  Email listmaster@xxxxxxxxxxxxxxxxxxxx.


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/