Please ignore/delete my previous email with identical subject,
 line wrapping ruined the formatting.

Purpose of this patch:

Locking to an external 1pps pulse with ts2phc is typically done
to assign traceability to a PHC clock, such that then this clock can be 
used to time stamp other events with a high precision and known accuracy.

This requires that the user only uses the PHC, when it is stably locked 
to the external pulse. This patch adds the 
   --systemd_pidfile=/run/ts2phc.pid config option, allowing to use ts2phc
as an forking-type deamon in a systemd.service.

When specified together with
   --servo_offset_threshold=x, ts2phc will run until the servo enters its
SERVO_LOCKED_STABLE (s3) state. It then forks, detaches the child and writes
the pid of the child into the pidfile and quits the main process. This enables
us to have other systemd.service to only start after the PHC lock is valid, and
by using BindsTo inother services, they even can be linked to stop (and later 
automatically restart) when the PHC is not locked stably. A typical 
application would be a traceable NTP server or grandmaster clock.

Signed-off-by: Jürgen Appel <j...@dfm.dk>
---
 1pps2phc.service | 42 ++++++++++++++++++++++++++++++++++++++++++
 config.c         |  1 +
 servo.c          |  4 ++++
 ts2phc.c         | 45 ++++++++++++++++++++++++++++++++++++++++++++-
 ts2phc.h         |  2 ++
 5 files changed, 93 insertions(+), 1 deletion(-)
 create mode 100644 1pps2phc.service

diff --git a/1pps2phc.service b/1pps2phc.service
new file mode 100644
index 0000000..00e5fda
--- /dev/null
+++ b/1pps2phc.service
@@ -0,0 +1,42 @@
+[Unit]
+
+# This example unit file shows how to configure a systemd-service that keeps
+# ptp3 locked to an external 100ms-hardware-1PPS pulse connected to ptp3.SDP0
+  
+Description=Lock phc3 to 1pps
+
+After=network.target
+
+# This service roughly sets the PHC clock to within 1 s of the intended offset
+After=initializePHC.service
+
+# Optional: As soon as we are locked, we want to use chrony to use /dev/ptp3 
as time source
+# Add the line "BindsTo=1pps2phc.service" to the [Unit] section in 
+# chrony's chrony.service configuration, and you are guaranteed that 
+# chrony is only running as long as your PHC is actually locked and is 
restarted when lock is lost.
+#Wants=chrony.service
+
+[Service]
+Type=forking
+PIDFile=/run/ts2phc_1pps%i.pid
+
+# We start up ts2phc and give the process up to 3 minutes to lock to within 
100 ns 
+TimeoutStartSec=180
+ExecStart=/usr/local/sbin/ts2phc -l 5 -c eth3 -s extpps \
+                                 --ts2phc.extts_correction=-35 \
+                                 --ts2phc.pin_index=0 \
+                                 --ts2phc.channel=0 \
+                                 --ts2phc.extts_polarity=both \
+                                 --ts2phc.pulsewidth=100000000 \
+                                 --message_tag=1pps \
+                                 --servo_offset_threshold=100 \
+                                 --systemd_pidfile=/run/ts2phc_1pps%i.pid
+
+Restart=on-failure
+
+# Optional: Enable an external Hardware-1PPS-output on ptp3.SDP1 as long as 
the lock is stable 
+ExecStartPost=/usr/local/sbin/testptp -d /dev/ptp3 -i 0 -L 1,2 -p 1000000000
+ExecStopPost=/usr/local/sbin/testptp -d /dev/ptp3 -i 0 -L 1,0
+
+[Install]
+WantedBy=multi-user.target
diff --git a/config.c b/config.c
index cb4421f..76a1056 100644
--- a/config.c
+++ b/config.c
@@ -329,6 +329,7 @@ struct config_item config_tab[] = {
        GLOB_ITEM_INT("socket_priority", 0, 0, 15),
        GLOB_ITEM_DBL("step_threshold", 0.0, 0.0, DBL_MAX),
        GLOB_ITEM_INT("step_window", 0, 0, INT_MAX),
+       GLOB_ITEM_STR("systemd_pidfile", NULL),
        GLOB_ITEM_INT("summary_interval", 0, INT_MIN, INT_MAX),
        PORT_ITEM_INT("syncReceiptTimeout", 0, 0, UINT8_MAX),
        GLOB_ITEM_INT("tc_spanning_tree", 0, 0, 1),
diff --git a/servo.c b/servo.c
index ea171cd..85fe665 100644
--- a/servo.c
+++ b/servo.c
@@ -107,6 +107,10 @@ static int check_offset_threshold(struct servo *s, int64_t 
offset)
                        if (s->curr_offset_values)
                                s->curr_offset_values--;
                } else {
+                       if (! s->curr_offset_values) {
+                               // lock became unstable after having been stable
+                               pr_info("servo got unlocked");
+                       }
                        s->curr_offset_values = s->num_offset_values;
                }
                return s->curr_offset_values ? 0 : 1;
diff --git a/ts2phc.c b/ts2phc.c
index 6a8cad9..13bf474 100644
--- a/ts2phc.c
+++ b/ts2phc.c
@@ -436,6 +436,9 @@ static void ts2phc_synchronize_clocks(struct ts2phc_private 
*priv, int autocfg)
        struct ts2phc_clock *c;
        int valid, err;
 
+       pid_t pid;
+       FILE *pid_file;
+
        if (autocfg) {
                if (!priv->ref_clock) {
                        pr_debug("no reference clock, skipping");
@@ -499,8 +502,45 @@ static void ts2phc_synchronize_clocks(struct 
ts2phc_private *priv, int autocfg)
                                goto servo_unlock;
                        }
                        break;
-               case SERVO_LOCKED:
                case SERVO_LOCKED_STABLE:
+                       if (priv->pidfile && !priv->is_forked) {
+                               priv->is_forked = true;
+                               pid = fork();
+                               switch (pid) {
+                               case -1:
+                                       pr_crit("fork failed");
+                                       exit(EXIT_FAILURE);
+                               case 0: /* child */
+                                       chdir("/");
+                                       close(0);
+                                       fopen("/dev/null", "r+");
+                                       dup2(0,1);
+                                       dup2(0,2);
+                                       setsid();
+                                       break;
+                               default: /* parent */
+                                       pr_info("forked & detached (pid=%d)",
+                                               pid);
+                                       pid_file = fopen(priv->pidfile, "w");
+                                       if (!pid_file) {
+                                               pr_err("cannot create pidfile");
+                                               _exit(EXIT_FAILURE);
+                                       } else {
+                                               fprintf(pid_file,"%d\n", pid);
+                                               fclose(pid_file);
+                                               _exit(EXIT_SUCCESS);
+                                       }
+                               }
+                       }
+                       if (clockadj_set_freq(c->clkid, -adj)) {
+                               goto servo_unlock;
+                       }
+                       break;
+               case SERVO_LOCKED:
+                       if (priv->is_forked) {
+                               // servo has relocked
+                               exit(EXIT_FAILURE);
+                       }
                        if (clockadj_set_freq(c->clkid, -adj)) {
                                goto servo_unlock;
                        }
@@ -670,6 +710,9 @@ int main(int argc, char *argv[])
        print_set_syslog(config_get_int(cfg, NULL, "use_syslog"));
        print_set_level(config_get_int(cfg, NULL, "logging_level"));
 
+       priv.pidfile = config_get_string(cfg, NULL, "systemd_pidfile");
+       priv.is_forked = false;
+
        STAILQ_INIT(&priv.sinks);
        priv.cfg = cfg;
 
diff --git a/ts2phc.h b/ts2phc.h
index 4833ded..6529f34 100644
--- a/ts2phc.h
+++ b/ts2phc.h
@@ -55,6 +55,8 @@ struct ts2phc_private {
        bool state_changed;
        LIST_HEAD(port_head, ts2phc_port) ports;
        LIST_HEAD(clock_head, ts2phc_clock) clocks;
+       char *pidfile;
+       bool is_forked;
 };
 
 struct ts2phc_clock *ts2phc_clock_add(struct ts2phc_private *priv,
-- 
2.34.1



_______________________________________________
Linuxptp-devel mailing list
Linuxptp-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxptp-devel

Reply via email to