[systemd-commits] stable Branch 'v215-stable' - 10 commits - src/libsystemd src/shared src/timesync

Michal Schmidt michich at kemper.freedesktop.org
Wed Sep 10 11:53:54 PDT 2014


 src/libsystemd/sd-event/sd-event.c |   35 +++++++++++--
 src/shared/time-util.c             |   19 +++++++
 src/shared/time-util.h             |    2 
 src/timesync/timesyncd.c           |   99 ++++++++++++++++++++++++++-----------
 src/timesync/timesyncd.h           |    2 
 5 files changed, 124 insertions(+), 33 deletions(-)

New commits:
commit 4242ef948fb91a1e65e34078b25f419950fc79e8
Author: Michal Schmidt <mschmidt at redhat.com>
Date:   Wed Sep 10 19:57:04 2014 +0200

    timesyncd: don't reset polling interval when reselecting server
    
    Upstream commit:
    commit 80cd2606b91ce2735a0609c6f964917cf12685aa
    Author: Kay Sievers <kay at vrfy.org>
    Date:   Tue Sep 2 14:33:59 2014 +0200
    
        timesyncd: don't reset polling interval when reselecting server
    
        Original patch from: Miroslav Lichvar <mlichvar at redhat.com>

diff --git a/src/timesync/timesyncd.c b/src/timesync/timesyncd.c
index 7470f4d..19ab1cf 100644
--- a/src/timesync/timesyncd.c
+++ b/src/timesync/timesyncd.c
@@ -800,7 +800,8 @@ static int manager_begin(Manager *m) {
         assert_return(m->current_server_address, -EHOSTUNREACH);
 
         m->missed_replies = NTP_MAX_MISSED_REPLIES;
-        m->poll_interval_usec = NTP_POLL_INTERVAL_MIN_SEC * USEC_PER_SEC;
+        if (m->poll_interval_usec == 0)
+                m->poll_interval_usec = NTP_POLL_INTERVAL_MIN_SEC * USEC_PER_SEC;
 
         sockaddr_pretty(&m->current_server_address->sockaddr.sa, m->current_server_address->socklen, true, &pretty);
         log_info("Using NTP server %s (%s).", strna(pretty), m->current_server_name->string);

commit 8269ab5ca37ca93f52ec1766d673e85887aa0ebe
Author: Michal Schmidt <mschmidt at redhat.com>
Date:   Wed Sep 10 19:55:59 2014 +0200

    timesyncd: allow two missed replies before reselecting server
    
    Upstream commit:
    commit e8206972be6a7ebeb198cd0d400bc7a94a6a5fc5
    Author: Miroslav Lichvar <mlichvar at redhat.com>
    Date:   Tue Sep 2 14:29:51 2014 +0200
    
        timesyncd: allow two missed replies before reselecting server
    
        After receiving a reply from the server, allow two missed replies before
        switching to another server to avoid unnecessary clock hopping when
        packets are getting lost in the network.
    
    Conflicts:
    	src/timesync/timesyncd-manager.c

diff --git a/src/timesync/timesyncd.c b/src/timesync/timesyncd.c
index 589c5ec..7470f4d 100644
--- a/src/timesync/timesyncd.c
+++ b/src/timesync/timesyncd.c
@@ -94,6 +94,9 @@
 /* Maximum acceptable root distance in seconds. */
 #define NTP_MAX_ROOT_DISTANCE           5.0
 
+/* Maximum number of missed replies before selecting another source. */
+#define NTP_MAX_MISSED_REPLIES          2
+
 /*
  * "NTP timestamps are represented as a 64-bit unsigned fixed-point number,
  * in seconds relative to 0h on 1 January 1900."
@@ -277,15 +280,18 @@ static int manager_send_request(Manager *m) {
                 return r;
         }
 
-        r = sd_event_add_time(
-                        m->event,
-                        &m->event_timeout,
-                        clock_boottime_or_monotonic(),
-                        now(clock_boottime_or_monotonic()) + TIMEOUT_USEC, 0,
-                        manager_timeout, m);
-        if (r < 0) {
-                log_error("Failed to arm timeout timer: %s", strerror(-r));
-                return r;
+        m->missed_replies++;
+        if (m->missed_replies > NTP_MAX_MISSED_REPLIES) {
+                r = sd_event_add_time(
+                                m->event,
+                                &m->event_timeout,
+                                clock_boottime_or_monotonic(),
+                                now(clock_boottime_or_monotonic()) + TIMEOUT_USEC, 0,
+                                manager_timeout, m);
+                if (r < 0) {
+                        log_error("Failed to arm timeout timer: %s", strerror(-r));
+                        return r;
+                }
         }
 
         return 0;
@@ -627,6 +633,8 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re
                 return 0;
         }
 
+        m->missed_replies = 0;
+
         /* check our "time cookie" (we just stored nanoseconds in the fraction field) */
         if (be32toh(ntpmsg.origin_time.sec) != m->trans_time.tv_sec + OFFSET_1900_1970 ||
             be32toh(ntpmsg.origin_time.frac) != m->trans_time.tv_nsec) {
@@ -791,6 +799,7 @@ static int manager_begin(Manager *m) {
         assert_return(m->current_server_name, -EHOSTUNREACH);
         assert_return(m->current_server_address, -EHOSTUNREACH);
 
+        m->missed_replies = NTP_MAX_MISSED_REPLIES;
         m->poll_interval_usec = NTP_POLL_INTERVAL_MIN_SEC * USEC_PER_SEC;
 
         sockaddr_pretty(&m->current_server_address->sockaddr.sa, m->current_server_address->socklen, true, &pretty);
diff --git a/src/timesync/timesyncd.h b/src/timesync/timesyncd.h
index 04d83f0..bcd14f7 100644
--- a/src/timesync/timesyncd.h
+++ b/src/timesync/timesyncd.h
@@ -61,6 +61,7 @@ struct Manager {
         ServerName *current_server_name;
         ServerAddress *current_server_address;
         int server_socket;
+        int missed_replies;
         uint64_t packet_count;
         sd_event_source *event_timeout;
 

commit 75d472e1a9a5bfbfc572443eece28322caef0792
Author: Michal Schmidt <mschmidt at redhat.com>
Date:   Wed Sep 10 19:44:24 2014 +0200

    timesyncd: wait before reconnecting to first server
    
    Upstream commit:
    commit 63463bf091949e0178b749016828ec400c106582
    Author: Miroslav Lichvar <mlichvar at redhat.com>
    Date:   Wed Aug 27 16:47:24 2014 +0200
    
        timesyncd: wait before reconnecting to first server
    
        When all servers are exhausted, wait for one poll interval before trying
        to connect again to the first server in the list. Also, keep increasing
        the polling interval to make sure a client not getting any valid replies
        will not send requests to any server more frequently than is allowed by
        the maximum polling interval.
    
    Conflicts:
    	src/timesync/timesyncd-manager.c

diff --git a/src/timesync/timesyncd.c b/src/timesync/timesyncd.c
index 5187df5..589c5ec 100644
--- a/src/timesync/timesyncd.c
+++ b/src/timesync/timesyncd.c
@@ -935,12 +935,32 @@ static int manager_connect(Manager *m) {
                 if (m->current_server_name && m->current_server_name->names_next)
                         m->current_server_name = m->current_server_name->names_next;
                 else {
+
                         if (!m->servers) {
                                 m->current_server_name = NULL;
                                 log_debug("No server found.");
                                 return 0;
                         }
 
+                        if (!m->exhausted_servers && m->poll_interval_usec) {
+                                log_debug("Waiting after exhausting servers.");
+                                r = sd_event_add_time(m->event, &m->event_retry, clock_boottime_or_monotonic(), now(clock_boottime_or_monotonic()) + m->poll_interval_usec, 0, manager_retry, m);
+                                if (r < 0) {
+                                        log_error("Failed to create retry timer: %s", strerror(-r));
+                                        return r;
+                                }
+
+                                m->exhausted_servers = true;
+
+                                /* Increase the polling interval */
+                                if (m->poll_interval_usec < NTP_POLL_INTERVAL_MAX_SEC * USEC_PER_SEC)
+                                        m->poll_interval_usec *= 2;
+
+                                return 0;
+                        }
+
+                        m->exhausted_servers = false;
+
                         m->current_server_name = m->servers;
                 }
 
@@ -1150,7 +1170,7 @@ static int manager_network_event_handler(sd_event_source *s, int fd, uint32_t re
         online = network_is_online();
 
         /* check if the client is currently connected */
-        connected = (m->server_socket != -1);
+        connected = (m->server_socket != -1) || m->exhausted_servers;
 
         if (connected && !online) {
                 log_info("No network connectivity, watching for changes.");
diff --git a/src/timesync/timesyncd.h b/src/timesync/timesyncd.h
index 4afe4b9..04d83f0 100644
--- a/src/timesync/timesyncd.h
+++ b/src/timesync/timesyncd.h
@@ -49,6 +49,7 @@ struct Manager {
         LIST_HEAD(ServerName, servers);
 
         RateLimit ratelimit;
+        bool exhausted_servers;
 
         /* network */
         sd_event_source *network_event_source;

commit c5b5c6b8cbf326031ef2de87a2268ecb10a3a44c
Author: Michal Schmidt <mschmidt at redhat.com>
Date:   Wed Sep 10 19:13:40 2014 +0200

    timesyncd: check root distance
    
    Upstream commit:
    commit 3af0442c52090f34ae7a1c8e6b6587c540c06896
    Author: Miroslav Lichvar <mlichvar at redhat.com>
    Date:   Wed Aug 27 16:47:20 2014 +0200
    
        timesyncd: check root distance
    
        NTPv4 servers don't reply with unsynchronized status when they lost
        synchronization, they only keep increasing the root dispersion and it's
        up to the client to decide at which point they no longer consider it
        synchronized.
    
        Ignore replies with root distance over 5 seconds.

diff --git a/src/timesync/timesyncd.c b/src/timesync/timesyncd.c
index 436aeae..5187df5 100644
--- a/src/timesync/timesyncd.c
+++ b/src/timesync/timesyncd.c
@@ -91,6 +91,9 @@
 #define NTP_FIELD_MODE(f)               ((f) & 7)
 #define NTP_FIELD(l, v, m)              (((l) << 6) | ((v) << 3) | (m))
 
+/* Maximum acceptable root distance in seconds. */
+#define NTP_MAX_ROOT_DISTANCE           5.0
+
 /*
  * "NTP timestamps are represented as a 64-bit unsigned fixed-point number,
  * in seconds relative to 0h on 1 January 1900."
@@ -136,6 +139,10 @@ static int manager_clock_watch_setup(Manager *m);
 static int manager_connect(Manager *m);
 static void manager_disconnect(Manager *m);
 
+static double ntp_ts_short_to_d(const struct ntp_ts_short *ts) {
+        return be16toh(ts->sec) + (be16toh(ts->frac) / 65536.0);
+}
+
 static double ntp_ts_to_d(const struct ntp_ts *ts) {
         return be32toh(ts->sec) + ((double)be32toh(ts->frac) / UINT_MAX);
 }
@@ -565,6 +572,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re
         ssize_t len;
         double origin, receive, trans, dest;
         double delay, offset;
+        double root_distance;
         bool spike;
         int leap_sec;
         int r;
@@ -650,6 +658,12 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re
                 return manager_connect(m);
         }
 
+        root_distance = ntp_ts_short_to_d(&ntpmsg.root_delay) / 2 + ntp_ts_short_to_d(&ntpmsg.root_dispersion);
+        if (root_distance > NTP_MAX_ROOT_DISTANCE) {
+                log_debug("Server has too large root distance. Disconnecting.");
+                return manager_connect(m);
+        }
+
         /* valid packet */
         m->pending = false;
         m->retry_interval = 0;
@@ -691,6 +705,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re
                   "  mode         : %u\n"
                   "  stratum      : %u\n"
                   "  precision    : %.6f sec (%d)\n"
+                  "  root distance: %.6f sec\n"
                   "  reference    : %.4s\n"
                   "  origin       : %.3f\n"
                   "  receive      : %.3f\n"
@@ -706,6 +721,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re
                   NTP_FIELD_MODE(ntpmsg.field),
                   ntpmsg.stratum,
                   exp2(ntpmsg.precision), ntpmsg.precision,
+                  root_distance,
                   ntpmsg.stratum == 1 ? ntpmsg.refid : "n/a",
                   origin - OFFSET_1900_1970,
                   receive - OFFSET_1900_1970,

commit 1cdb867fa07aa9a1fa698dd4eb8fa26e145eecf1
Author: Michal Schmidt <mschmidt at redhat.com>
Date:   Wed Sep 10 19:12:50 2014 +0200

    timesyncd: get kernel timestamp in nanoseconds
    
    Upstream commit:
    commit 487a36821ea214a73e1d0dcbd6d84123b50d1135
    Author: Miroslav Lichvar <mlichvar at redhat.com>
    Date:   Wed Aug 27 16:47:19 2014 +0200
    
        timesyncd: get kernel timestamp in nanoseconds

diff --git a/src/timesync/timesyncd.c b/src/timesync/timesyncd.c
index d123f0a..436aeae 100644
--- a/src/timesync/timesyncd.c
+++ b/src/timesync/timesyncd.c
@@ -144,10 +144,6 @@ static double ts_to_d(const struct timespec *ts) {
         return ts->tv_sec + (1.0e-9 * ts->tv_nsec);
 }
 
-static double tv_to_d(const struct timeval *tv) {
-        return tv->tv_sec + (1.0e-6 * tv->tv_usec);
-}
-
 static double square(double d) {
         return d * d;
 }
@@ -565,7 +561,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re
                 .msg_namelen = sizeof(server_addr),
         };
         struct cmsghdr *cmsg;
-        struct timeval *recv_time;
+        struct timespec *recv_time;
         ssize_t len;
         double origin, receive, trans, dest;
         double delay, offset;
@@ -608,8 +604,8 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re
                         continue;
 
                 switch (cmsg->cmsg_type) {
-                case SCM_TIMESTAMP:
-                        recv_time = (struct timeval *) CMSG_DATA(cmsg);
+                case SCM_TIMESTAMPNS:
+                        recv_time = (struct timespec *) CMSG_DATA(cmsg);
                         break;
                 }
         }
@@ -680,7 +676,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re
         origin = ts_to_d(&m->trans_time) + OFFSET_1900_1970;
         receive = ntp_ts_to_d(&ntpmsg.recv_time);
         trans = ntp_ts_to_d(&ntpmsg.trans_time);
-        dest = tv_to_d(recv_time) + OFFSET_1900_1970;
+        dest = ts_to_d(recv_time) + OFFSET_1900_1970;
 
         offset = ((receive - origin) + (trans - dest)) / 2;
         delay = (dest - origin) - (trans - receive);
@@ -762,7 +758,7 @@ static int manager_listen_setup(Manager *m) {
         if (r < 0)
                 return -errno;
 
-        r = setsockopt(m->server_socket, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on));
+        r = setsockopt(m->server_socket, SOL_SOCKET, SO_TIMESTAMPNS, &on, sizeof(on));
         if (r < 0)
                 return -errno;
 

commit 355043d3d3778d4516ab410c7da461d53f0de0a9
Author: Michal Schmidt <mschmidt at redhat.com>
Date:   Wed Sep 10 19:10:05 2014 +0200

    timesyncd: fix calculation of transmit time
    
    Upstream commit:
    commit 73c76e6330d31e1d04454fd7408dd56b4eedca9f
    Author: Miroslav Lichvar <mlichvar at redhat.com>
    Date:   Wed Aug 27 16:47:18 2014 +0200
    
        timesyncd: fix calculation of transmit time
    
        The kernel timestamp (recv_time) is made earlier than current time
        (now_ts), use the timestamp captured before sending packet directly.

diff --git a/src/timesync/timesyncd.c b/src/timesync/timesyncd.c
index dc00b2f..d123f0a 100644
--- a/src/timesync/timesyncd.c
+++ b/src/timesync/timesyncd.c
@@ -565,7 +565,6 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re
                 .msg_namelen = sizeof(server_addr),
         };
         struct cmsghdr *cmsg;
-        struct timespec now_ts;
         struct timeval *recv_time;
         ssize_t len;
         double origin, receive, trans, dest;
@@ -678,8 +677,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re
          *  The round-trip delay, d, and system clock offset, t, are defined as:
          *  d = (T4 - T1) - (T3 - T2)     t = ((T2 - T1) + (T3 - T4)) / 2"
          */
-        assert_se(clock_gettime(clock_boottime_or_monotonic(), &now_ts) >= 0);
-        origin = tv_to_d(recv_time) - (ts_to_d(&now_ts) - ts_to_d(&m->trans_time_mon)) + OFFSET_1900_1970;
+        origin = ts_to_d(&m->trans_time) + OFFSET_1900_1970;
         receive = ntp_ts_to_d(&ntpmsg.recv_time);
         trans = ntp_ts_to_d(&ntpmsg.trans_time);
         dest = tv_to_d(recv_time) + OFFSET_1900_1970;

commit e5ef9861f95f46b0b6462b7c4de62cd470ead17f
Author: Michal Schmidt <mschmidt at redhat.com>
Date:   Wed Sep 10 19:00:56 2014 +0200

    timesyncd: check if stratum is valid
    
    Upstream commit:
    commit 07610e108e2d3f046da683a3a69c4d5cccd2cf8e
    Author: Miroslav Lichvar <mlichvar at redhat.com>
    Date:   Wed Aug 27 16:47:17 2014 +0200
    
        timesyncd: check if stratum is valid

diff --git a/src/timesync/timesyncd.c b/src/timesync/timesyncd.c
index efe9544..dc00b2f 100644
--- a/src/timesync/timesyncd.c
+++ b/src/timesync/timesyncd.c
@@ -639,7 +639,8 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re
                 return manager_connect(m);
         }
 
-        if (NTP_FIELD_LEAP(ntpmsg.field) == NTP_LEAP_NOTINSYNC) {
+        if (NTP_FIELD_LEAP(ntpmsg.field) == NTP_LEAP_NOTINSYNC ||
+            ntpmsg.stratum == 0 || ntpmsg.stratum >= 16) {
                 log_debug("Server is not synchronized. Disconnecting.");
                 return manager_connect(m);
         }

commit 908c733f6676b0154b669d116aad80851d97d024
Author: Michal Schmidt <mschmidt at redhat.com>
Date:   Wed Sep 10 20:34:38 2014 +0200

    timesyncd: always use CLOCK_BOOTTIME if we can
    
    Upstream commit:
    commit 6a5c7b7e41a036bfdc2474b4583fcfdd358a6db6
    Author: Lennart Poettering <lennart at poettering.net>
    Date:   Sun Aug 10 23:40:48 2014 +0200
    
        timesyncd: always use CLOCK_BOOTTIME if we can
    
        After all we want to compare a monotonically increasing clock with the
        remote clock, hence we shouldn't ignore system suspend periods.

diff --git a/src/timesync/timesyncd.c b/src/timesync/timesyncd.c
index 19af9f9..efe9544 100644
--- a/src/timesync/timesyncd.c
+++ b/src/timesync/timesyncd.c
@@ -245,7 +245,7 @@ static int manager_send_request(Manager *m) {
          * The actual value does not matter, We do not care about the correct
          * NTP UINT_MAX fraction; we just pass the plain nanosecond value.
          */
-        assert_se(clock_gettime(CLOCK_MONOTONIC, &m->trans_time_mon) >= 0);
+        assert_se(clock_gettime(clock_boottime_or_monotonic(), &m->trans_time_mon) >= 0);
         assert_se(clock_gettime(CLOCK_REALTIME, &m->trans_time) >= 0);
         ntpmsg.trans_time.sec = htobe32(m->trans_time.tv_sec + OFFSET_1900_1970);
         ntpmsg.trans_time.frac = htobe32(m->trans_time.tv_nsec);
@@ -277,8 +277,8 @@ static int manager_send_request(Manager *m) {
         r = sd_event_add_time(
                         m->event,
                         &m->event_timeout,
-                        CLOCK_MONOTONIC,
-                        now(CLOCK_MONOTONIC) + TIMEOUT_USEC, 0,
+                        clock_boottime_or_monotonic(),
+                        now(clock_boottime_or_monotonic()) + TIMEOUT_USEC, 0,
                         manager_timeout, m);
         if (r < 0) {
                 log_error("Failed to arm timeout timer: %s", strerror(-r));
@@ -308,7 +308,7 @@ static int manager_arm_timer(Manager *m, usec_t next) {
         }
 
         if (m->event_timer) {
-                r = sd_event_source_set_time(m->event_timer, now(CLOCK_MONOTONIC) + next);
+                r = sd_event_source_set_time(m->event_timer, now(clock_boottime_or_monotonic()) + next);
                 if (r < 0)
                         return r;
 
@@ -318,8 +318,8 @@ static int manager_arm_timer(Manager *m, usec_t next) {
         return sd_event_add_time(
                         m->event,
                         &m->event_timer,
-                        CLOCK_MONOTONIC,
-                        now(CLOCK_MONOTONIC) + next, 0,
+                        clock_boottime_or_monotonic(),
+                        now(clock_boottime_or_monotonic()) + next, 0,
                         manager_timer, m);
 }
 
@@ -677,7 +677,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re
          *  The round-trip delay, d, and system clock offset, t, are defined as:
          *  d = (T4 - T1) - (T3 - T2)     t = ((T2 - T1) + (T3 - T4)) / 2"
          */
-        assert_se(clock_gettime(CLOCK_MONOTONIC, &now_ts) >= 0);
+        assert_se(clock_gettime(clock_boottime_or_monotonic(), &now_ts) >= 0);
         origin = tv_to_d(recv_time) - (ts_to_d(&now_ts) - ts_to_d(&m->trans_time_mon)) + OFFSET_1900_1970;
         receive = ntp_ts_to_d(&ntpmsg.recv_time);
         trans = ntp_ts_to_d(&ntpmsg.trans_time);
@@ -904,7 +904,7 @@ static int manager_connect(Manager *m) {
         if (!ratelimit_test(&m->ratelimit)) {
                 log_debug("Slowing down attempts to contact servers.");
 
-                r = sd_event_add_time(m->event, &m->event_retry, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + RETRY_USEC, 0, manager_retry, m);
+                r = sd_event_add_time(m->event, &m->event_retry, clock_boottime_or_monotonic(), now(clock_boottime_or_monotonic()) + RETRY_USEC, 0, manager_retry, m);
                 if (r < 0) {
                         log_error("Failed to create retry timer: %s", strerror(-r));
                         return r;

commit 9ec9316b80b531793d27aea177f13d33adef22e8
Author: Michal Schmidt <mschmidt at redhat.com>
Date:   Wed Sep 10 20:34:36 2014 +0200

    time-util: add clock_boottime_or_monotonic
    
    Upstream commit:
    commit 77ff2de999b7ea6b1b4a3a218fbd9d62bb07cd54
    Author: Tom Gundersen <teg at jklm.no>
    Date:   Thu Jul 24 18:36:37 2014 +0200
    
        time-util: add clock_boottime_or_monotonic
    
        CLOCK_BOOTTIME is not supported by timerfd on older kernels, so for the time beeing,
        use this helper instead which will fallback to CLOCK_MONOTONIC if CLOCK_BOOTTIME is
        not supported.
    
    Conflicts:
    	src/shared/time-util.c
    	src/shared/time-util.h

diff --git a/src/shared/time-util.c b/src/shared/time-util.c
index 8e5de77..d5c5217 100644
--- a/src/shared/time-util.c
+++ b/src/shared/time-util.c
@@ -22,6 +22,7 @@
 #include <time.h>
 #include <string.h>
 #include <sys/timex.h>
+#include <sys/timerfd.h>
 
 #include "util.h"
 #include "time-util.h"
@@ -826,3 +827,21 @@ bool ntp_synced(void) {
 
         return true;
 }
+
+clockid_t clock_boottime_or_monotonic(void) {
+        static clockid_t clock = -1;
+        int fd;
+
+        if (clock != -1)
+                return clock;
+
+        fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
+        if (fd < 0)
+                clock = CLOCK_MONOTONIC;
+        else {
+                safe_close(fd);
+                clock = CLOCK_BOOTTIME;
+        }
+
+        return clock;
+}
diff --git a/src/shared/time-util.h b/src/shared/time-util.h
index 34ba6c1..ad9a4fd 100644
--- a/src/shared/time-util.h
+++ b/src/shared/time-util.h
@@ -95,3 +95,5 @@ int parse_sec(const char *t, usec_t *usec);
 int parse_nsec(const char *t, nsec_t *nsec);
 
 bool ntp_synced(void);
+
+clockid_t clock_boottime_or_monotonic(void);

commit df1b5312d9bc17853d51a37d01319164ed4e0dc5
Author: Michal Schmidt <mschmidt at redhat.com>
Date:   Wed Sep 10 20:34:09 2014 +0200

    sd-event: add support for CLOCK_BOOTTIME
    
    Upstream commit:
    commit a854881616afbe4c4f55396d3fc2f922bbbe716b
    Author: Tom Gundersen <teg at jklm.no>
    Date:   Thu Jul 24 16:08:07 2014 +0200
    
        sd-event: add support for CLOCK_BOOTTIME
    
        This requires a very recent kernel (3.15), so care should be taken
        when using this functionality.

diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
index 53f1904..ecab8f0 100644
--- a/src/libsystemd/sd-event/sd-event.c
+++ b/src/libsystemd/sd-event/sd-event.c
@@ -43,6 +43,7 @@
 typedef enum EventSourceType {
         SOURCE_IO,
         SOURCE_TIME_REALTIME,
+        SOURCE_TIME_BOOTTIME,
         SOURCE_TIME_MONOTONIC,
         SOURCE_TIME_REALTIME_ALARM,
         SOURCE_TIME_BOOTTIME_ALARM,
@@ -56,7 +57,7 @@ typedef enum EventSourceType {
         _SOURCE_EVENT_SOURCE_TYPE_INVALID = -1
 } EventSourceType;
 
-#define EVENT_SOURCE_IS_TIME(t) IN_SET((t), SOURCE_TIME_REALTIME, SOURCE_TIME_MONOTONIC, SOURCE_TIME_REALTIME_ALARM, SOURCE_TIME_BOOTTIME_ALARM)
+#define EVENT_SOURCE_IS_TIME(t) IN_SET((t), SOURCE_TIME_REALTIME, SOURCE_TIME_BOOTTIME, SOURCE_TIME_MONOTONIC, SOURCE_TIME_REALTIME_ALARM, SOURCE_TIME_BOOTTIME_ALARM)
 
 struct sd_event_source {
         unsigned n_ref;
@@ -142,10 +143,11 @@ struct sd_event {
         Prioq *pending;
         Prioq *prepare;
 
-        /* timerfd_create() only supports these four clocks so far. We
+        /* timerfd_create() only supports these five clocks so far. We
          * can add support for more clocks when the kernel learns to
          * deal with them, too. */
         struct clock_data realtime;
+        struct clock_data boottime;
         struct clock_data monotonic;
         struct clock_data realtime_alarm;
         struct clock_data boottime_alarm;
@@ -377,6 +379,7 @@ static void event_free(sd_event *e) {
         safe_close(e->watchdog_fd);
 
         free_clock_data(&e->realtime);
+        free_clock_data(&e->boottime);
         free_clock_data(&e->monotonic);
         free_clock_data(&e->realtime_alarm);
         free_clock_data(&e->boottime_alarm);
@@ -403,8 +406,8 @@ _public_ int sd_event_new(sd_event** ret) {
                 return -ENOMEM;
 
         e->n_ref = 1;
-        e->signal_fd = e->watchdog_fd = e->epoll_fd = e->realtime.fd = e->monotonic.fd = e->realtime_alarm.fd = e->boottime_alarm.fd = -1;
-        e->realtime.next = e->monotonic.next = e->realtime_alarm.next = e->boottime_alarm.next = (usec_t) -1;
+        e->signal_fd = e->watchdog_fd = e->epoll_fd = e->realtime.fd = e->boottime.fd = e->monotonic.fd = e->realtime_alarm.fd = e->boottime_alarm.fd = -1;
+        e->realtime.next = e->boottime.next = e->monotonic.next = e->realtime_alarm.next = e->boottime_alarm.next = (usec_t) -1;
         e->original_pid = getpid();
         e->perturb = (usec_t) -1;
 
@@ -517,6 +520,9 @@ static clockid_t event_source_type_to_clock(EventSourceType t) {
         case SOURCE_TIME_REALTIME:
                 return CLOCK_REALTIME;
 
+        case SOURCE_TIME_BOOTTIME:
+                return CLOCK_BOOTTIME;
+
         case SOURCE_TIME_MONOTONIC:
                 return CLOCK_MONOTONIC;
 
@@ -538,6 +544,9 @@ static EventSourceType clock_to_event_source_type(clockid_t clock) {
         case CLOCK_REALTIME:
                 return SOURCE_TIME_REALTIME;
 
+        case CLOCK_BOOTTIME:
+                return SOURCE_TIME_BOOTTIME;
+
         case CLOCK_MONOTONIC:
                 return SOURCE_TIME_MONOTONIC;
 
@@ -560,6 +569,9 @@ static struct clock_data* event_get_clock_data(sd_event *e, EventSourceType t) {
         case SOURCE_TIME_REALTIME:
                 return &e->realtime;
 
+        case SOURCE_TIME_BOOTTIME:
+                return &e->boottime;
+
         case SOURCE_TIME_MONOTONIC:
                 return &e->monotonic;
 
@@ -593,6 +605,7 @@ static void source_disconnect(sd_event_source *s) {
                 break;
 
         case SOURCE_TIME_REALTIME:
+        case SOURCE_TIME_BOOTTIME:
         case SOURCE_TIME_MONOTONIC:
         case SOURCE_TIME_REALTIME_ALARM:
         case SOURCE_TIME_BOOTTIME_ALARM: {
@@ -1382,6 +1395,7 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
                         break;
 
                 case SOURCE_TIME_REALTIME:
+                case SOURCE_TIME_BOOTTIME:
                 case SOURCE_TIME_MONOTONIC:
                 case SOURCE_TIME_REALTIME_ALARM:
                 case SOURCE_TIME_BOOTTIME_ALARM: {
@@ -1444,6 +1458,7 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
                         break;
 
                 case SOURCE_TIME_REALTIME:
+                case SOURCE_TIME_BOOTTIME:
                 case SOURCE_TIME_MONOTONIC:
                 case SOURCE_TIME_REALTIME_ALARM:
                 case SOURCE_TIME_BOOTTIME_ALARM: {
@@ -2002,6 +2017,7 @@ static int source_dispatch(sd_event_source *s) {
                 break;
 
         case SOURCE_TIME_REALTIME:
+        case SOURCE_TIME_BOOTTIME:
         case SOURCE_TIME_MONOTONIC:
         case SOURCE_TIME_REALTIME_ALARM:
         case SOURCE_TIME_BOOTTIME_ALARM:
@@ -2202,6 +2218,10 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) {
         if (r < 0)
                 goto finish;
 
+        r = event_arm_timer(e, &e->boottime);
+        if (r < 0)
+                goto finish;
+
         r = event_arm_timer(e, &e->monotonic);
         if (r < 0)
                 goto finish;
@@ -2236,6 +2256,8 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) {
 
                 if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_TIME_REALTIME))
                         r = flush_timer(e, e->realtime.fd, ev_queue[i].events, &e->realtime.next);
+                else if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_TIME_BOOTTIME))
+                        r = flush_timer(e, e->boottime.fd, ev_queue[i].events, &e->boottime.next);
                 else if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_TIME_MONOTONIC))
                         r = flush_timer(e, e->monotonic.fd, ev_queue[i].events, &e->monotonic.next);
                 else if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_TIME_REALTIME_ALARM))
@@ -2261,6 +2283,10 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) {
         if (r < 0)
                 goto finish;
 
+        r = process_timer(e, e->timestamp_boottime, &e->boottime);
+        if (r < 0)
+                goto finish;
+
         r = process_timer(e, e->timestamp.monotonic, &e->monotonic);
         if (r < 0)
                 goto finish;
@@ -2366,6 +2392,7 @@ _public_ int sd_event_now(sd_event *e, clockid_t clock, uint64_t *usec) {
                 *usec = e->timestamp.monotonic;
                 break;
 
+        case CLOCK_BOOTTIME:
         case CLOCK_BOOTTIME_ALARM:
                 *usec = e->timestamp_boottime;
                 break;



More information about the systemd-commits mailing list