portclock.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include "u.h"
  10. #include "../port/lib.h"
  11. #include "mem.h"
  12. #include "dat.h"
  13. #include "fns.h"
  14. #include "ureg.h"
  15. struct Timers
  16. {
  17. Lock l;
  18. Timer *head;
  19. };
  20. static Timers timers[MACHMAX];
  21. uint32_t intrcount[MACHMAX];
  22. uint32_t fcallcount[MACHMAX];
  23. static int64_t
  24. tadd(Timers *tt, Timer *nt)
  25. {
  26. int64_t when;
  27. Timer *t, **last;
  28. /* Called with tt locked */
  29. assert(nt->tt == nil);
  30. switch(nt->tmode){
  31. default:
  32. panic("timer");
  33. break;
  34. case Trelative:
  35. if(nt->tns <= 0)
  36. nt->tns = 1;
  37. nt->twhen = fastticks(nil) + ns2fastticks(nt->tns);
  38. break;
  39. case Tperiodic:
  40. /*
  41. * Periodic timers must have a period of at least 100µs.
  42. */
  43. assert(nt->tns >= 100000);
  44. if(nt->twhen == 0){
  45. /*
  46. * Look for another timer at the
  47. * same frequency for combining.
  48. */
  49. for(t = tt->head; t; t = t->tnext){
  50. if(t->tmode == Tperiodic && t->tns == nt->tns)
  51. break;
  52. }
  53. if(t)
  54. nt->twhen = t->twhen;
  55. else
  56. nt->twhen = fastticks(nil);
  57. }
  58. /*
  59. * The new time must be in the future.
  60. * ns2fastticks() can return 0 if the tod clock
  61. * has been adjusted by, e.g. timesync.
  62. */
  63. when = ns2fastticks(nt->tns);
  64. if(when == 0)
  65. when = 1;
  66. nt->twhen += when;
  67. break;
  68. }
  69. for(last = &tt->head; (t = *last) != nil; last = &t->tnext){
  70. if(t->twhen > nt->twhen)
  71. break;
  72. }
  73. nt->tnext = *last;
  74. *last = nt;
  75. nt->tt = tt;
  76. if(last == &tt->head)
  77. return nt->twhen;
  78. return 0;
  79. }
  80. static int64_t
  81. tdel(Timer *dt)
  82. {
  83. Timer *t, **last;
  84. Timers *tt;
  85. tt = dt->tt;
  86. if(tt == nil)
  87. return 0;
  88. for(last = &tt->head; (t = *last) != nil; last = &t->tnext){
  89. if(t == dt){
  90. assert(dt->tt);
  91. dt->tt = nil;
  92. *last = t->tnext;
  93. break;
  94. }
  95. }
  96. if(last == &tt->head && tt->head)
  97. return tt->head->twhen;
  98. return 0;
  99. }
  100. /* add or modify a timer */
  101. void
  102. timeradd(Timer *nt)
  103. {
  104. Timers *tt;
  105. int64_t when;
  106. /* Must lock Timer struct before Timers struct */
  107. ilock(&nt->l);
  108. if((tt = nt->tt) != nil){
  109. ilock(&tt->l);
  110. tdel(nt);
  111. iunlock(&tt->l);
  112. }
  113. tt = &timers[machp()->machno];
  114. ilock(&tt->l);
  115. when = tadd(tt, nt);
  116. if(when)
  117. timerset(when);
  118. iunlock(&tt->l);
  119. iunlock(&nt->l);
  120. }
  121. void
  122. timerdel(Timer *dt)
  123. {
  124. Timers *tt;
  125. int64_t when;
  126. ilock(&dt->l);
  127. if((tt = dt->tt) != nil){
  128. ilock(&tt->l);
  129. when = tdel(dt);
  130. if(when && tt == &timers[machp()->machno])
  131. timerset(tt->head->twhen);
  132. iunlock(&tt->l);
  133. }
  134. iunlock(&dt->l);
  135. }
  136. void
  137. hzclock(Ureg *ur)
  138. {
  139. Proc *up = externup();
  140. uintptr_t pc;
  141. machp()->ticks++;
  142. if(machp()->machno == 0)
  143. sys->ticks = machp()->ticks;
  144. pc = userpc(ur);
  145. if(machp()->proc)
  146. machp()->proc->pc = pc;
  147. if(machp()->mmuflush){
  148. if(up)
  149. mmuflush();
  150. machp()->mmuflush = 0;
  151. }
  152. accounttime();
  153. kmapinval();
  154. if(kproftimer != nil)
  155. kproftimer(pc);
  156. oprof_alarm_handler(ur);
  157. if(machp()->online == 0)
  158. return;
  159. if(active.exiting) {
  160. print("someone's exiting\n");
  161. exit(0);
  162. }
  163. checkalarms();
  164. if(up && up->state == Running)
  165. hzsched(); /* in proc.c */
  166. }
  167. void
  168. timerintr(Ureg *u, int64_t j)
  169. {
  170. Timer *t;
  171. Timers *tt;
  172. int64_t when, now;
  173. int callhzclock;
  174. intrcount[machp()->machno]++;
  175. callhzclock = 0;
  176. tt = &timers[machp()->machno];
  177. now = fastticks(nil);
  178. ilock(&tt->l);
  179. while((t = tt->head) != nil){
  180. /*
  181. * No need to ilock t here: any manipulation of t
  182. * requires tdel(t) and this must be done with a
  183. * lock to tt held. We have tt, so the tdel will
  184. * wait until we're done
  185. */
  186. when = t->twhen;
  187. if(when > now){
  188. timerset(when);
  189. iunlock(&tt->l);
  190. if(callhzclock)
  191. hzclock(u);
  192. return;
  193. }
  194. tt->head = t->tnext;
  195. assert(t->tt == tt);
  196. t->tt = nil;
  197. fcallcount[machp()->machno]++;
  198. iunlock(&tt->l);
  199. if(t->tf)
  200. (*t->tf)(u, t);
  201. else
  202. callhzclock++;
  203. ilock(&tt->l);
  204. if(t->tmode == Tperiodic)
  205. tadd(tt, t);
  206. }
  207. iunlock(&tt->l);
  208. }
  209. void
  210. timersinit(void)
  211. {
  212. Timer *t;
  213. /*
  214. * T->tf == nil means the HZ clock for this processor.
  215. */
  216. todinit();
  217. t = malloc(sizeof(*t));
  218. t->tmode = Tperiodic;
  219. t->tt = nil;
  220. t->tns = 1000000000/HZ;
  221. t->tf = nil;
  222. timeradd(t);
  223. }
  224. Timer*
  225. addclock0link(void (*f)(void), int ms)
  226. {
  227. Timer *nt;
  228. int64_t when;
  229. /* Synchronize to hztimer if ms is 0 */
  230. nt = malloc(sizeof(Timer));
  231. if(ms == 0)
  232. ms = 1000/HZ;
  233. nt->tns = (int64_t)ms*1000000LL;
  234. nt->tmode = Tperiodic;
  235. nt->tt = nil;
  236. nt->tf = (void (*)(Ureg*, Timer*))f;
  237. ilock(&timers[0].l);
  238. when = tadd(&timers[0], nt);
  239. if(when)
  240. timerset(when);
  241. iunlock(&timers[0].l);
  242. return nt;
  243. }
  244. /*
  245. * This tk2ms avoids overflows that the macro version is prone to.
  246. * It is a LOT slower so shouldn't be used if you're just converting
  247. * a delta.
  248. */
  249. uint32_t
  250. tk2ms(uint32_t ticks)
  251. {
  252. uint64_t t, hz;
  253. t = ticks;
  254. hz = HZ;
  255. t *= 1000L;
  256. t = t/hz;
  257. ticks = t;
  258. return ticks;
  259. }
  260. uint32_t
  261. ms2tk(uint32_t ms)
  262. {
  263. /* avoid overflows at the cost of precision */
  264. if(ms >= 1000000000/HZ)
  265. return (ms/1000)*HZ;
  266. return (ms*HZ+500)/1000;
  267. }