portclock.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  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;
  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; 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; 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);
  108. if(tt = nt->tt){
  109. ilock(tt);
  110. tdel(nt);
  111. iunlock(tt);
  112. }
  113. tt = &timers[m->machno];
  114. ilock(tt);
  115. when = tadd(tt, nt);
  116. if(when)
  117. timerset(when);
  118. iunlock(tt);
  119. iunlock(nt);
  120. }
  121. void
  122. timerdel(Timer *dt)
  123. {
  124. Timers *tt;
  125. int64_t when;
  126. ilock(dt);
  127. if(tt = dt->tt){
  128. ilock(tt);
  129. when = tdel(dt);
  130. if(when && tt == &timers[m->machno])
  131. timerset(tt->head->twhen);
  132. iunlock(tt);
  133. }
  134. iunlock(dt);
  135. }
  136. void
  137. hzclock(Ureg *ur)
  138. {
  139. uintptr pc;
  140. m->ticks++;
  141. if(m->machno == 0)
  142. sys->ticks = m->ticks;
  143. pc = userpc(ur);
  144. if(m->proc)
  145. m->proc->pc = pc;
  146. if(m->mmuflush){
  147. if(up)
  148. mmuflush();
  149. m->mmuflush = 0;
  150. }
  151. accounttime();
  152. kmapinval();
  153. if(kproftimer != nil)
  154. kproftimer(pc);
  155. if(m->online == 0)
  156. return;
  157. if(active.exiting) {
  158. iprint("someone's exiting\n");
  159. exit(0);
  160. }
  161. checkalarms();
  162. if(up && up->state == Running)
  163. hzsched(); /* in proc.c */
  164. }
  165. void
  166. timerintr(Ureg *u, int64_t)
  167. {
  168. Timer *t;
  169. Timers *tt;
  170. int64_t when, now;
  171. int callhzclock;
  172. intrcount[m->machno]++;
  173. callhzclock = 0;
  174. tt = &timers[m->machno];
  175. now = fastticks(nil);
  176. ilock(tt);
  177. while(t = tt->head){
  178. /*
  179. * No need to ilock t here: any manipulation of t
  180. * requires tdel(t) and this must be done with a
  181. * lock to tt held. We have tt, so the tdel will
  182. * wait until we're done
  183. */
  184. when = t->twhen;
  185. if(when > now){
  186. timerset(when);
  187. iunlock(tt);
  188. if(callhzclock)
  189. hzclock(u);
  190. return;
  191. }
  192. tt->head = t->tnext;
  193. assert(t->tt == tt);
  194. t->tt = nil;
  195. fcallcount[m->machno]++;
  196. iunlock(tt);
  197. if(t->tf)
  198. (*t->tf)(u, t);
  199. else
  200. callhzclock++;
  201. ilock(tt);
  202. if(t->tmode == Tperiodic)
  203. tadd(tt, t);
  204. }
  205. iunlock(tt);
  206. }
  207. void
  208. timersinit(void)
  209. {
  210. Timer *t;
  211. /*
  212. * T->tf == nil means the HZ clock for this processor.
  213. */
  214. todinit();
  215. t = malloc(sizeof(*t));
  216. t->tmode = Tperiodic;
  217. t->tt = nil;
  218. t->tns = 1000000000/HZ;
  219. t->tf = nil;
  220. timeradd(t);
  221. }
  222. Timer*
  223. addclock0link(void (*f)(void), int ms)
  224. {
  225. Timer *nt;
  226. int64_t when;
  227. /* Synchronize to hztimer if ms is 0 */
  228. nt = malloc(sizeof(Timer));
  229. if(ms == 0)
  230. ms = 1000/HZ;
  231. nt->tns = (int64_t)ms*1000000LL;
  232. nt->tmode = Tperiodic;
  233. nt->tt = nil;
  234. nt->tf = (void (*)(Ureg*, Timer*))f;
  235. ilock(&timers[0]);
  236. when = tadd(&timers[0], nt);
  237. if(when)
  238. timerset(when);
  239. iunlock(&timers[0]);
  240. return nt;
  241. }
  242. /*
  243. * This tk2ms avoids overflows that the macro version is prone to.
  244. * It is a LOT slower so shouldn't be used if you're just converting
  245. * a delta.
  246. */
  247. uint32_t
  248. tk2ms(uint32_t ticks)
  249. {
  250. uint64_t t, hz;
  251. t = ticks;
  252. hz = HZ;
  253. t *= 1000L;
  254. t = t/hz;
  255. ticks = t;
  256. return ticks;
  257. }
  258. uint32_t
  259. ms2tk(uint32_t ms)
  260. {
  261. /* avoid overflows at the cost of precision */
  262. if(ms >= 1000000000/HZ)
  263. return (ms/1000)*HZ;
  264. return (ms*HZ+500)/1000;
  265. }