Author: Not specified Language: c
Description: Not specified Timestamp: 2017-08-23 14:00:44 +0000
View raw paste Reply
  1. /* Helper functions for fiddling with timespec structures.
  2.  * Written by Daniel Collins (2017)
  3.  *
  4.  * Released to public domain.
  5. */
  6.  
  7. /* --- NEGATIVE VALUES ---
  8.  *
  9.  * There doesn't seem to be any widely-accepted standard for how to represent
  10.  * negative values in a timespec structure. POSIX defines some functions for
  11.  * munging timeVAL structures, but doesn't define how they behave when either
  12.  * or both of the values are positive.
  13.  *
  14.  * This library allows either field to be negative, but >0 and <0 values cannot
  15.  * be mixed in the same timespec.
  16. */
  17.  
  18. #include <time.h>
  19. #include <stdbool.h>
  20.  
  21. /* struct timespec timespec_normalise(struct timespec ts)
  22.  *
  23.  * Returns a normalised version of a timespec structure, according to the
  24.  * following rules:
  25.  *
  26.  * 1) If tv_nsec is >1,000,000,00 or <-1,000,000,000, flatten the surplus
  27.  *    nanoseconds into the tv_sec field.
  28.  *
  29.  * 2) If tv_sec is >0 and tv_nsec is <0, decrement tv_sec and roll tv_nsec up
  30.  *    to represent the same value on the positive side of the new tv_sec.
  31.  *
  32.  * 3) If tv_sec is <0 and tv_nsec is >0, increment tv_sec and roll tv_nsec down
  33.  *    to represent the same value on the negative side of the new tv_sec.
  34. */
  35. struct timespec timespec_normalise(struct timespec ts)
  36. {
  37.         while(ts.tv_nsec >= 1000000000)
  38.         {
  39.                 ++(ts.tv_sec);
  40.                 ts.tv_nsec -= 1000000000;
  41.         }
  42.        
  43.         while(ts.tv_nsec <= -1000000000)
  44.         {
  45.                 --(ts.tv_sec);
  46.                 ts.tv_nsec += 1000000000;
  47.         }
  48.        
  49.         if(ts.tv_nsec < 0 && ts.tv_sec > 0)
  50.         {
  51.                 /* Negative nanoseconds while seconds is positive.
  52.                  * Decrement tv_sec and roll tv_nsec over.
  53.                 */
  54.                
  55.                 --(ts.tv_sec);
  56.                 ts.tv_nsec = 1000000000 - (-1 * ts.tv_nsec);
  57.         }
  58.         else if(ts.tv_nsec > 0 && ts.tv_sec < 0)
  59.         {
  60.                 /* Positive nanoseconds while seconds is negative.
  61.                  * Increment tv_sec and roll tv_nsec over.
  62.                 */
  63.                
  64.                 ++(ts.tv_sec);
  65.                 ts.tv_nsec = -1000000000 - (-1 * ts.tv_nsec);
  66.         }
  67.        
  68.         return ts;
  69. }
  70.  
  71. /* struct timespec timespec_add(struct timespec ts1, struct timespec ts2)
  72.  *
  73.  * Add two timespec structures together and return their sum.
  74. */
  75. struct timespec timespec_add(struct timespec ts1, struct timespec ts2)
  76. {
  77.         ts1.tv_sec  += ts2.tv_sec;
  78.         ts1.tv_nsec += ts2.tv_nsec;
  79.        
  80.         return timespec_normalise(ts1);
  81. }
  82.  
  83. /* struct timespec timespec_sub(struct timespec ts1, struct timespec ts2)
  84.  *
  85.  * Return the value of ts1 after subtracting ts2.
  86. */
  87. struct timespec timespec_sub(struct timespec ts1, struct timespec ts2)
  88. {
  89.         ts1.tv_sec  -= ts2.tv_sec;
  90.         ts1.tv_nsec -= ts2.tv_nsec;
  91.        
  92.         return timespec_normalise(ts1);
  93. }
  94.  
  95. /* bool timespec_eq(struct timespec ts1, struct timespec ts2)
  96.  *
  97.  * Return true if the two timespec structures are equal.
  98. */
  99. bool timespec_eq(struct timespec ts1, struct timespec ts2)
  100. {
  101.         return (ts1.tv_sec == ts2.tv_sec && ts1.tv_nsec == ts2.tv_nsec);
  102. }
  103.  
  104. /* bool timespec_gt(struct timespec ts1, struct timespec ts2)
  105.  *
  106.  * Return true if ts1 is greater than ts2.
  107. */
  108. bool timespec_gt(struct timespec ts1, struct timespec ts2)
  109. {
  110.         return (ts1.tv_sec > ts2.tv_sec || (ts1.tv_sec == ts2.tv_sec && ts1.tv_nsec > ts2.tv_nsec));
  111. }
  112.  
  113. /* bool timespec_ge(struct timespec ts1, struct timespec ts2)
  114.  *
  115.  * Return true if ts1 is greater than or equal to ts2.
  116. */
  117. bool timespec_ge(struct timespec ts1, struct timespec ts2)
  118. {
  119.         return (ts1.tv_sec >= ts2.tv_sec || (ts1.tv_sec == ts2.tv_sec && ts1.tv_nsec >= ts2.tv_nsec));
  120. }
  121.  
  122. /* bool timespec_lt(struct timespec ts1, struct timespec ts2)
  123.  *
  124.  * Return true if ts1 is less than ts2.
  125. */
  126. bool timespec_lt(struct timespec ts1, struct timespec ts2)
  127. {
  128.         return (ts1.tv_sec < ts2.tv_sec || (ts1.tv_sec == ts2.tv_sec && ts1.tv_nsec < ts2.tv_nsec));
  129. }
  130.  
  131. /* bool timespec_le(struct timespec ts1, struct timespec ts2)
  132.  *
  133.  * Return true if ts1 is less than or equal to ts2.
  134. */
  135. bool timespec_le(struct timespec ts1, struct timespec ts2)
  136. {
  137.         return (ts1.tv_sec <= ts2.tv_sec || (ts1.tv_sec == ts2.tv_sec && ts1.tv_nsec <= ts2.tv_nsec));
  138. }
  139.  
  140. /* double timespec_to_double(struct timespec ts)
  141.  *
  142.  * Convert a timespec structure to a fractional number of seconds represented
  143.  * as a double.
  144. */
  145. double timespec_to_double(struct timespec ts)
  146. {
  147.         return ((double)(ts.tv_sec) + ((double)(ts.tv_nsec) / 1000000000));
  148. }
  149.  
  150. #ifdef TEST
  151. #include <stdio.h>
  152.  
  153. #define TEST_NORMALISE(ts_sec, ts_nsec, expect_sec, expect_nsec) { \
  154.         struct timespec in  = { .tv_sec = ts_sec, .tv_nsec = ts_nsec }; \
  155.         struct timespec got = timespec_normalise(in); \
  156.         if(got.tv_sec != expect_sec || got.tv_nsec != expect_nsec) \
  157.         { \
  158.                 printf("timespec_normalise({%ld, %ld}) returned wrong values\n", (long)(ts_sec), (long)(ts_nsec)); \
  159.                 printf("    Expected: {%ld, %ld}\n", (long)(expect_sec), (long)(expect_nsec)); \
  160.                 printf("    Got:      {%ld, %ld}\n", (long)(got.tv_sec), (long)(got.tv_nsec)); \
  161.                 ++result; \
  162.         } \
  163. }
  164.  
  165. #define TEST_ADD(ts1_sec, ts1_nsec, ts2_sec, ts2_nsec, expect_sec, expect_nsec) { \
  166.         struct timespec ts1 = { .tv_sec = ts1_sec, .tv_nsec = ts1_nsec }; \
  167.         struct timespec ts2 = { .tv_sec = ts2_sec, .tv_nsec = ts2_nsec }; \
  168.         struct timespec got = timespec_add(ts1, ts2); \
  169.         if(got.tv_sec != expect_sec || got.tv_nsec != expect_nsec) \
  170.         { \
  171.                 printf("timespec_add({%ld, %ld}, {%ld, %ld}) returned wrong values\n", \
  172.                         (long)(ts1_sec), (long)(ts1_nsec), (long)(ts2_sec), (long)(ts2_nsec)); \
  173.                 printf("    Expected: {%ld, %ld}\n", (long)(expect_sec), (long)(expect_nsec)); \
  174.                 printf("    Got:      {%ld, %ld}\n", (long)(got.tv_sec), (long)(got.tv_nsec)); \
  175.                 ++result; \
  176.         } \
  177. }
  178.  
  179. #define TEST_SUB(ts1_sec, ts1_nsec, ts2_sec, ts2_nsec, expect_sec, expect_nsec) { \
  180.         struct timespec ts1 = { .tv_sec = ts1_sec, .tv_nsec = ts1_nsec }; \
  181.         struct timespec ts2 = { .tv_sec = ts2_sec, .tv_nsec = ts2_nsec }; \
  182.         struct timespec got = timespec_sub(ts1, ts2); \
  183.         if(got.tv_sec != expect_sec || got.tv_nsec != expect_nsec) \
  184.         { \
  185.                 printf("timespec_sub({%ld, %ld}, {%ld, %ld}) returned wrong values\n", \
  186.                         (long)(ts1_sec), (long)(ts1_nsec), (long)(ts2_sec), (long)(ts2_nsec)); \
  187.                 printf("    Expected: {%ld, %ld}\n", (long)(expect_sec), (long)(expect_nsec)); \
  188.                 printf("    Got:      {%ld, %ld}\n", (long)(got.tv_sec), (long)(got.tv_nsec)); \
  189.                 ++result; \
  190.         } \
  191. }
  192.  
  193. int main()
  194. {
  195.         int result = 0;
  196.        
  197.         TEST_NORMALISE(0,0,           0,0);
  198.         TEST_NORMALISE(0,1000000000,  1,0);
  199.         TEST_NORMALISE(0,-1000000000, -1,0);
  200.         TEST_NORMALISE(1,-500000000,  0,500000000);
  201.         TEST_NORMALISE(1,-499999999,  0,500000001);
  202.         TEST_NORMALISE(-1,500000000,  0,-500000000);
  203.        
  204.         TEST_ADD(0,0,         0,0,         0,0);
  205.         TEST_ADD(0,0,         1,0,         1,0);
  206.         TEST_ADD(1,0,         0,0,         1,0);
  207.         TEST_ADD(1,0,         1,0,         2,0);
  208.         TEST_ADD(1,500000000, 1,0,         2,500000000);
  209.         TEST_ADD(1,0,         1,500000000, 2,500000000);
  210.         TEST_ADD(1,500000000, 1,500000000, 3,0);
  211.         TEST_ADD(1,500000000, 1,499999999, 2,999999999);
  212.         TEST_ADD(1,500000000, 1,500000000, 3,0);
  213.         TEST_ADD(1,999999999, 1,999999999, 3,999999998);
  214.         TEST_ADD(0,500000000, 1,500000000, 2,0);
  215.         TEST_ADD(1,500000000, 0,500000000, 2,0);
  216.        
  217.         TEST_SUB(0,0,         0,0,         0,0);
  218.         TEST_SUB(1,0,         0,0,         1,0);
  219.         TEST_SUB(1,0,         1,0,         0,0);
  220.         TEST_SUB(1,500000000, 0,500000000, 1,0);
  221.         TEST_SUB(5,500000000, 2,999999999, 2,500000001);
  222.         TEST_SUB(0,0,         1,0,         -1,0);
  223.         TEST_SUB(0,500000000, 1,500000000, -1,0);
  224.         TEST_SUB(0,0,         1,500000000, -1,-500000000);
  225.         TEST_SUB(1,0,         1,500000000, 0,-500000000);
  226.         TEST_SUB(1,0,         1,499999999, 0,-499999999);
  227.        
  228.         if(result > 0)
  229.         {
  230.                 printf("%d tests failed\n", result);
  231.         }
  232.         else{
  233.                 printf("All tests passed\n");
  234.         }
  235.        
  236.         return result;
  237. }
  238. #endif
  239.  
View raw paste Reply