portclock.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "io.h"
  7. #include "ureg.h"
  8. struct Timers
  9. {
  10. Lock;
  11. Timer *head;
  12. };
  13. static Timers timers[MAXMACH];
  14. ulong intrcount[MAXMACH];
  15. ulong fcallcount[MAXMACH];
  16. static uvlong
  17. tadd(Timers *tt, Timer *nt)
  18. {
  19. Timer *t, **last;
  20. /* Called with tt locked */
  21. assert(nt->tt == nil);
  22. switch(nt->tmode){
  23. default:
  24. panic("timer");
  25. break;
  26. case Trelative:
  27. assert(nt->tns > 0);
  28. nt->twhen = fastticks(nil) + ns2fastticks(nt->tns);
  29. break;
  30. case Tabsolute:
  31. nt->twhen = tod2fastticks(nt->tns);
  32. break;
  33. case Tperiodic:
  34. assert(nt->tns >= 100000); /* At least 100 µs period */
  35. if(nt->twhen == 0){
  36. /* look for another timer at same frequency for combining */
  37. for(t = tt->head; t; t = t->tnext){
  38. if(t->tmode == Tperiodic && t->tns == nt->tns)
  39. break;
  40. }
  41. if (t)
  42. nt->twhen = t->twhen;
  43. else
  44. nt->twhen = fastticks(nil);
  45. }
  46. nt->twhen += ns2fastticks(nt->tns);
  47. break;
  48. }
  49. for(last = &tt->head; t = *last; last = &t->tnext){
  50. if(t->twhen > nt->twhen)
  51. break;
  52. }
  53. nt->tnext = *last;
  54. *last = nt;
  55. nt->tt = tt;
  56. if(last == &tt->head)
  57. return nt->twhen;
  58. return 0;
  59. }
  60. static uvlong
  61. tdel(Timer *dt)
  62. {
  63. Timer *t, **last;
  64. Timers *tt;
  65. tt = dt->tt;
  66. if (tt == nil)
  67. return 0;
  68. for(last = &tt->head; t = *last; last = &t->tnext){
  69. if(t == dt){
  70. assert(dt->tt);
  71. dt->tt = nil;
  72. *last = t->tnext;
  73. break;
  74. }
  75. }
  76. if(last == &tt->head && tt->head)
  77. return tt->head->twhen;
  78. return 0;
  79. }
  80. /* add or modify a timer */
  81. void
  82. timeradd(Timer *nt)
  83. {
  84. Timers *tt;
  85. vlong when;
  86. if (nt->tmode == Tabsolute){
  87. when = todget(nil);
  88. if (nt->tns <= when){
  89. // if (nt->tns + MS2NS(10) <= when) /* small deviations will happen */
  90. // print("timeradd (%lld %lld) %lld too early 0x%lux\n",
  91. // when, nt->tns, when - nt->tns, getcallerpc(&nt));
  92. nt->tns = when;
  93. }
  94. }
  95. /* Must lock Timer struct before Timers struct */
  96. ilock(nt);
  97. if(tt = nt->tt){
  98. ilock(tt);
  99. tdel(nt);
  100. iunlock(tt);
  101. }
  102. tt = &timers[m->machno];
  103. ilock(tt);
  104. when = tadd(tt, nt);
  105. if(when)
  106. timerset(when);
  107. iunlock(tt);
  108. iunlock(nt);
  109. }
  110. void
  111. timerdel(Timer *dt)
  112. {
  113. Timers *tt;
  114. uvlong when;
  115. ilock(dt);
  116. if(tt = dt->tt){
  117. ilock(tt);
  118. when = tdel(dt);
  119. if(when && tt == &timers[m->machno])
  120. timerset(tt->head->twhen);
  121. iunlock(tt);
  122. }
  123. iunlock(dt);
  124. }
  125. void
  126. hzclock(Ureg *ur)
  127. {
  128. m->ticks++;
  129. if(m->proc)
  130. m->proc->pc = ur->pc;
  131. if(m->flushmmu){
  132. if(up)
  133. flushmmu();
  134. m->flushmmu = 0;
  135. }
  136. accounttime();
  137. kmapinval();
  138. if(kproftimer != nil)
  139. kproftimer(ur->pc);
  140. if((active.machs&(1<<m->machno)) == 0)
  141. return;
  142. if(active.exiting) {
  143. print("someone's exiting\n");
  144. exit(0);
  145. }
  146. checkalarms();
  147. if(up && up->state == Running)
  148. hzsched(); /* in proc.c */
  149. }
  150. void
  151. timerintr(Ureg *u, uvlong)
  152. {
  153. Timer *t;
  154. Timers *tt;
  155. uvlong when, now;
  156. int callhzclock;
  157. static int sofar;
  158. intrcount[m->machno]++;
  159. callhzclock = 0;
  160. tt = &timers[m->machno];
  161. now = fastticks(nil);
  162. ilock(tt);
  163. while(t = tt->head){
  164. /*
  165. * No need to ilock t here: any manipulation of t
  166. * requires tdel(t) and this must be done with a
  167. * lock to tt held. We have tt, so the tdel will
  168. * wait until we're done
  169. */
  170. when = t->twhen;
  171. if(when > now){
  172. timerset(when);
  173. iunlock(tt);
  174. if(callhzclock)
  175. hzclock(u);
  176. return;
  177. }
  178. tt->head = t->tnext;
  179. assert(t->tt == tt);
  180. t->tt = nil;
  181. fcallcount[m->machno]++;
  182. iunlock(tt);
  183. if(t->tf)
  184. (*t->tf)(u, t);
  185. else
  186. callhzclock++;
  187. ilock(tt);
  188. if(t->tmode == Tperiodic)
  189. tadd(tt, t);
  190. }
  191. iunlock(tt);
  192. }
  193. void
  194. timersinit(void)
  195. {
  196. Timer *t;
  197. todinit();
  198. t = malloc(sizeof(*t));
  199. t->tmode = Tperiodic;
  200. t->tt = nil;
  201. t->tns = 1000000000/HZ;
  202. t->tf = nil;
  203. timeradd(t);
  204. }
  205. Timer*
  206. addclock0link(void (*f)(void), int ms)
  207. {
  208. Timer *nt;
  209. uvlong when;
  210. /* Synchronize to hztimer if ms is 0 */
  211. nt = malloc(sizeof(Timer));
  212. if(ms == 0)
  213. ms = 1000/HZ;
  214. nt->tns = (vlong)ms*1000000LL;
  215. nt->tmode = Tperiodic;
  216. nt->tt = nil;
  217. nt->tf = (void (*)(Ureg*, Timer*))f;
  218. ilock(&timers[0]);
  219. when = tadd(&timers[0], nt);
  220. if(when)
  221. timerset(when);
  222. iunlock(&timers[0]);
  223. return nt;
  224. }
  225. /*
  226. * This tk2ms avoids overflows that the macro version is prone to.
  227. * It is a LOT slower so shouldn't be used if you're just converting
  228. * a delta.
  229. */
  230. ulong
  231. tk2ms(ulong ticks)
  232. {
  233. uvlong t, hz;
  234. t = ticks;
  235. hz = HZ;
  236. t *= 1000L;
  237. t = t/hz;
  238. ticks = t;
  239. return ticks;
  240. }
  241. ulong
  242. ms2tk(ulong ms)
  243. {
  244. /* avoid overflows at the cost of precision */
  245. if(ms >= 1000000000/HZ)
  246. return (ms/1000)*HZ;
  247. return (ms*HZ+500)/1000;
  248. }