Author: asomers
Date: Tue Aug 13 19:27:23 2019
New Revision: 350998
URL: https://svnweb.freebsd.org/changeset/base/350998

Log:
  ping: use the monotonic clock to measure durations
  
  Submitted by: Ján Sučan <sucan...@gmail.com>
  MFC after:    2 weeks
  Sponsored by: Google, inc. (Google Summer of Code 2019)
  Differential Revision:        https://reviews.freebsd.org/D21245

Modified:
  head/sbin/ping/ping.c

Modified: head/sbin/ping/ping.c
==============================================================================
--- head/sbin/ping/ping.c       Tue Aug 13 19:24:17 2019        (r350997)
+++ head/sbin/ping/ping.c       Tue Aug 13 19:27:23 2019        (r350998)
@@ -96,6 +96,7 @@ __FBSDID("$FreeBSD$");
 #include <stdlib.h>
 #include <string.h>
 #include <sysexits.h>
+#include <time.h>
 #include <unistd.h>
 
 #define        INADDR_LEN      ((int)sizeof(in_addr_t))
@@ -119,7 +120,7 @@ __FBSDID("$FreeBSD$");
 
 struct tv32 {
        int32_t tv32_sec;
-       int32_t tv32_usec;
+       int32_t tv32_nsec;
 };
 
 /* various options */
@@ -217,11 +218,10 @@ static char *pr_addr(struct in_addr);
 static char *pr_ntime(n_time);
 static void pr_icmph(struct icmp *);
 static void pr_iph(struct ip *);
-static void pr_pack(char *, int, struct sockaddr_in *, struct timeval *);
+static void pr_pack(char *, int, struct sockaddr_in *, struct timespec *);
 static void pr_retip(struct ip *);
 static void status(int);
 static void stopit(int);
-static void tvsub(struct timeval *, const struct timeval *);
 static void usage(void) __dead2;
 
 int
@@ -229,7 +229,7 @@ main(int argc, char *const *argv)
 {
        struct sockaddr_in from, sock_in;
        struct in_addr ifaddr;
-       struct timeval last, intvl;
+       struct timespec last, intvl;
        struct iovec iov;
        struct ip *ip;
        struct msghdr msg;
@@ -247,7 +247,7 @@ main(int argc, char *const *argv)
        long ltmp;
        int almost_done, ch, df, hold, i, icmp_len, mib[4], preload;
        int ssend_errno, srecv_errno, tos, ttl;
-       char ctrl[CMSG_SPACE(sizeof(struct timeval))];
+       char ctrl[CMSG_SPACE(sizeof(struct timespec))];
        char hnamebuf[MAXHOSTNAMELEN], snamebuf[MAXHOSTNAMELEN];
 #ifdef IP_OPTIONS
        char rspace[MAX_IPOPTLEN];      /* record route space */
@@ -871,19 +871,19 @@ main(int argc, char *const *argv)
                while (preload--)       /* fire off them quickies */
                        pinger();
        }
-       (void)gettimeofday(&last, NULL);
+       (void)clock_gettime(CLOCK_MONOTONIC, &last);
 
        if (options & F_FLOOD) {
                intvl.tv_sec = 0;
-               intvl.tv_usec = 10000;
+               intvl.tv_nsec = 10000000;
        } else {
                intvl.tv_sec = interval / 1000;
-               intvl.tv_usec = interval % 1000 * 1000;
+               intvl.tv_nsec = interval % 1000 * 1000000;
        }
 
        almost_done = 0;
        while (!finish_up) {
-               struct timeval now, timeout;
+               struct timespec now, timeout;
                fd_set rfds;
                int cc, n;
 
@@ -892,24 +892,16 @@ main(int argc, char *const *argv)
                        errx(EX_OSERR, "descriptor too large");
                FD_ZERO(&rfds);
                FD_SET(srecv, &rfds);
-               (void)gettimeofday(&now, NULL);
-               timeout.tv_sec = last.tv_sec + intvl.tv_sec - now.tv_sec;
-               timeout.tv_usec = last.tv_usec + intvl.tv_usec - now.tv_usec;
-               while (timeout.tv_usec < 0) {
-                       timeout.tv_usec += 1000000;
-                       timeout.tv_sec--;
-               }
-               while (timeout.tv_usec >= 1000000) {
-                       timeout.tv_usec -= 1000000;
-                       timeout.tv_sec++;
-               }
+               (void)clock_gettime(CLOCK_MONOTONIC, &now);
+               timespecadd(&last, &intvl, &timeout);
+               timespecsub(&timeout, &now, &timeout);
                if (timeout.tv_sec < 0)
-                       timerclear(&timeout);
-               n = select(srecv + 1, &rfds, NULL, NULL, &timeout);
+                       timespecclear(&timeout);
+               n = pselect(srecv + 1, &rfds, NULL, NULL, &timeout, NULL);
                if (n < 0)
                        continue;       /* Must be EINTR. */
                if (n == 1) {
-                       struct timeval *tv = NULL;
+                       struct timespec *tv = NULL;
 #ifdef SO_TIMESTAMP
                        struct cmsghdr *cmsg = (struct cmsghdr *)&ctrl;
 
@@ -932,7 +924,7 @@ main(int argc, char *const *argv)
                        }
 #endif
                        if (tv == NULL) {
-                               (void)gettimeofday(&now, NULL);
+                               (void)clock_gettime(CLOCK_MONOTONIC, &now);
                                tv = &now;
                        }
                        pr_pack((char *)packet, cc, &from, tv);
@@ -956,17 +948,17 @@ main(int argc, char *const *argv)
                                if (almost_done)
                                        break;
                                almost_done = 1;
-                               intvl.tv_usec = 0;
+                               intvl.tv_nsec = 0;
                                if (nreceived) {
                                        intvl.tv_sec = 2 * tmax / 1000;
                                        if (!intvl.tv_sec)
                                                intvl.tv_sec = 1;
                                } else {
                                        intvl.tv_sec = waittime / 1000;
-                                       intvl.tv_usec = waittime % 1000 * 1000;
+                                       intvl.tv_nsec = waittime % 1000 * 
1000000;
                                }
                        }
-                       (void)gettimeofday(&last, NULL);
+                       (void)clock_gettime(CLOCK_MONOTONIC, &last);
                        if (ntransmitted - nreceived - 1 > nmissedmax) {
                                nmissedmax = ntransmitted - nreceived - 1;
                                if (options & F_MISSED)
@@ -1003,13 +995,13 @@ stopit(int sig __unused)
  *     Compose and transmit an ICMP ECHO REQUEST packet.  The IP packet
  * will be added on by the kernel.  The ID field is our UNIX process ID,
  * and the sequence number is an ascending integer.  The first TIMEVAL_LEN
- * bytes of the data portion are used to hold a UNIX "timeval" struct in
+ * bytes of the data portion are used to hold a UNIX "timespec" struct in
  * host byte-order, to compute the round-trip time.
  */
 static void
 pinger(void)
 {
-       struct timeval now;
+       struct timespec now;
        struct tv32 tv32;
        struct ip *ip;
        struct icmp *icp;
@@ -1027,13 +1019,18 @@ pinger(void)
        CLR(ntransmitted % mx_dup_ck);
 
        if ((options & F_TIME) || timing) {
-               (void)gettimeofday(&now, NULL);
-
-               tv32.tv32_sec = htonl(now.tv_sec);
-               tv32.tv32_usec = htonl(now.tv_usec);
+               (void)clock_gettime(CLOCK_MONOTONIC, &now);
+               /*
+                * Truncate seconds down to 32 bits in order
+                * to fit the timestamp within 8 bytes of the
+                * packet. We're only concerned with
+                * durations, not absolute times.
+                */
+               tv32.tv32_sec = (uint32_t)htonl(now.tv_sec);
+               tv32.tv32_nsec = (uint32_t)htonl(now.tv_nsec);
                if (options & F_TIME)
                        icp->icmp_otime = htonl((now.tv_sec % (24*60*60))
-                               * 1000 + now.tv_usec / 1000);
+                               * 1000 + now.tv_nsec / 1000000);
                if (timing)
                        bcopy((void *)&tv32,
                            (void *)&outpack[ICMP_MINLEN + phdr_len],
@@ -1079,7 +1076,7 @@ pinger(void)
  * program to be run without having intermingled output (or statistics!).
  */
 static void
-pr_pack(char *buf, int cc, struct sockaddr_in *from, struct timeval *tv)
+pr_pack(char *buf, int cc, struct sockaddr_in *from, struct timespec *tv)
 {
        struct in_addr ina;
        u_char *cp, *dp;
@@ -1112,7 +1109,7 @@ pr_pack(char *buf, int cc, struct sockaddr_in *from, s
                ++nreceived;
                triptime = 0.0;
                if (timing) {
-                       struct timeval tv1;
+                       struct timespec tv1;
                        struct tv32 tv32;
 #ifndef icmp_data
                        tp = &icp->icmp_ip;
@@ -1126,10 +1123,10 @@ pr_pack(char *buf, int cc, struct sockaddr_in *from, s
                                /* Copy to avoid alignment problems: */
                                memcpy(&tv32, tp, sizeof(tv32));
                                tv1.tv_sec = ntohl(tv32.tv32_sec);
-                               tv1.tv_usec = ntohl(tv32.tv32_usec);
-                               tvsub(tv, &tv1);
+                               tv1.tv_nsec = ntohl(tv32.tv32_nsec);
+                               timespecsub(tv, &tv1, tv);
                                triptime = ((double)tv->tv_sec) * 1000.0 +
-                                   ((double)tv->tv_usec) / 1000.0;
+                                   ((double)tv->tv_nsec) / 1000000.0;
                                tsum += triptime;
                                tsumsq += triptime * triptime;
                                if (triptime < tmin)
@@ -1381,22 +1378,6 @@ in_cksum(u_short *addr, int len)
        sum += (sum >> 16);                     /* add carry */
        answer = ~sum;                          /* truncate to 16 bits */
        return(answer);
-}
-
-/*
- * tvsub --
- *     Subtract 2 timeval structs:  out = out - in.  Out is assumed to
- * be >= in.
- */
-static void
-tvsub(struct timeval *out, const struct timeval *in)
-{
-
-       if ((out->tv_usec -= in->tv_usec) < 0) {
-               --out->tv_sec;
-               out->tv_usec += 1000000;
-       }
-       out->tv_sec -= in->tv_sec;
 }
 
 /*
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to