tod.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "../port/error.h"
  7. // compute nanosecond epoch time from the fastest ticking clock
  8. // on the system. converting the time to nanoseconds requires
  9. // the following formula
  10. //
  11. // t = (((1000000000<<31)/f)*ticks)>>31
  12. //
  13. // where
  14. //
  15. // 'f' is the clock frequency
  16. // 'ticks' are clock ticks
  17. //
  18. // to avoid too much calculation in todget(), we calculate
  19. //
  20. // mult = (1000000000<<31)/f
  21. //
  22. // each time f is set. f is normally set by a user level
  23. // program writing to /dev/fastclock.
  24. //
  25. // We assume that the cpu's of a multiprocessor are synchronized.
  26. // This assumption needs to be questioned with each new architecture.
  27. // frequency of the tod clock
  28. #define TODFREQ 1000000000ULL
  29. struct {
  30. ulong cnt;
  31. Lock;
  32. vlong multiplier; // t = off + (multiplier*ticks)>>31
  33. vlong hz; // frequency of fast clock
  34. vlong last; // last reading of fast clock
  35. vlong off; // offset from epoch to last
  36. vlong lasttime; // last return value from todget
  37. vlong delta; // add 'delta' each slow clock tick from sstart to send
  38. ulong sstart; // ...
  39. ulong send; // ...
  40. } tod;
  41. void
  42. todinit(void)
  43. {
  44. ilock(&tod);
  45. tod.last = fastticks((uvlong*)&tod.hz);
  46. iunlock(&tod);
  47. todsetfreq(tod.hz);
  48. addclock0link(todfix, 100);
  49. }
  50. //
  51. // calculate multiplier
  52. //
  53. void
  54. todsetfreq(vlong f)
  55. {
  56. ilock(&tod);
  57. tod.hz = f;
  58. /* calculate multiplier for time conversion */
  59. tod.multiplier = (TODFREQ<<31)/f;
  60. iunlock(&tod);
  61. }
  62. //
  63. // Set the time of day struct
  64. //
  65. void
  66. todset(vlong t, vlong delta, int n)
  67. {
  68. ilock(&tod);
  69. if(t >= 0){
  70. tod.off = t;
  71. tod.last = fastticks(nil);
  72. tod.lasttime = 0;
  73. tod.delta = 0;
  74. tod.sstart = tod.send;
  75. } else {
  76. if(n <= 0)
  77. n = 1;
  78. n *= HZ;
  79. if(delta < 0 && n > -delta)
  80. n = -delta;
  81. if(delta > 0 && n > delta)
  82. n = delta;
  83. delta = delta/n;
  84. tod.sstart = MACHP(0)->ticks;
  85. tod.send = tod.sstart + n;
  86. tod.delta = delta;
  87. }
  88. iunlock(&tod);
  89. }
  90. //
  91. // get time of day
  92. //
  93. vlong
  94. todget(vlong *ticksp)
  95. {
  96. uvlong x;
  97. vlong ticks, diff;
  98. ulong t;
  99. if(tod.hz == 0)
  100. ticks = fastticks((uvlong*)&tod.hz);
  101. else
  102. ticks = fastticks(nil);
  103. // since 64 bit loads are not atomic, we have to lock around them
  104. ilock(&tod);
  105. tod.cnt++;
  106. // add in correction
  107. if(tod.sstart != tod.send){
  108. t = MACHP(0)->ticks;
  109. if(t >= tod.send)
  110. t = tod.send;
  111. tod.off = tod.off + tod.delta*(t - tod.sstart);
  112. tod.sstart = t;
  113. }
  114. // convert to epoch
  115. diff = ticks - tod.last;
  116. x = (diff * tod.multiplier) >> 31;
  117. x = x + tod.off;
  118. // time can't go backwards
  119. if(x < tod.lasttime)
  120. x = tod.lasttime;
  121. else
  122. tod.lasttime = x;
  123. iunlock(&tod);
  124. if(ticksp != nil)
  125. *ticksp = ticks;
  126. return x;
  127. }
  128. //
  129. // called regularly to avoid calculation overflows
  130. //
  131. void
  132. todfix(void)
  133. {
  134. vlong ticks, diff;
  135. uvlong x;
  136. ticks = fastticks(nil);
  137. diff = ticks - tod.last;
  138. if(diff > tod.hz){
  139. ilock(&tod);
  140. // convert to epoch
  141. x = diff * tod.multiplier;
  142. x = x >> 31;
  143. x = x + tod.off;
  144. // protect against overflows
  145. tod.last = ticks;
  146. tod.off = x;
  147. iunlock(&tod);
  148. }
  149. }
  150. long
  151. seconds(void)
  152. {
  153. vlong x;
  154. int i;
  155. x = todget(nil);
  156. x = x/TODFREQ;
  157. i = x;
  158. return i;
  159. }
  160. // convert milliseconds to fast ticks
  161. //
  162. uvlong
  163. ms2fastticks(ulong ms)
  164. {
  165. if(tod.hz == 0)
  166. fastticks((uvlong*)&tod.hz);
  167. return (tod.hz*ms)/1000ULL;
  168. }