portclock.c 5.0 KB

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