taslock.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  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 "../port/edf.h"
  15. /*
  16. * measure max lock cycles and max lock waiting time.
  17. */
  18. #define LOCKCYCLES 0
  19. uint64_t maxlockcycles;
  20. uint64_t maxilockcycles;
  21. uintptr maxlockpc;
  22. uintptr maxilockpc;
  23. Lockstats lockstats;
  24. Waitstats waitstats;
  25. Lock waitstatslk;
  26. static void
  27. newwaitstats(void)
  28. {
  29. if(waitstats.pcs != nil)
  30. return;
  31. waitstats.pcs = malloc(NWstats * sizeof waitstats.pcs[0]);
  32. waitstats.ns = malloc(NWstats * sizeof waitstats.ns[0]);
  33. waitstats.wait = malloc(NWstats * sizeof waitstats.wait[0]);
  34. waitstats.total = malloc(NWstats * sizeof waitstats.total[0]);
  35. waitstats.type = malloc(NWstats * sizeof waitstats.type[0]);
  36. }
  37. void
  38. startwaitstats(int on)
  39. {
  40. newwaitstats();
  41. mfence();
  42. waitstats.on = on;
  43. print("lockstats %s\n", on?"on":"off");
  44. }
  45. void
  46. clearwaitstats(void)
  47. {
  48. newwaitstats();
  49. memset(waitstats.ns, 0, NWstats * sizeof(int));
  50. memset(waitstats.wait, 0, NWstats * sizeof(uint64_t));
  51. memset(waitstats.total, 0, NWstats * sizeof(uint64_t));
  52. }
  53. void
  54. addwaitstat(uintptr pc, uint64_t t0, int type)
  55. {
  56. uint i;
  57. uint64_t w;
  58. if(waitstats.on == 0)
  59. return;
  60. cycles(&w);
  61. w -= t0;
  62. mfence();
  63. for(i = 0; i < NWstats; i++)
  64. if(waitstats.pcs[i] == pc){
  65. ainc(&waitstats.ns[i]);
  66. if(w > waitstats.wait[i])
  67. waitstats.wait[i] = w; /* race but ok */
  68. waitstats.total[i] += w; /* race but ok */
  69. return;
  70. }
  71. if(!canlock(&waitstatslk))
  72. return;
  73. for(i = 0; i < NWstats; i++)
  74. if(waitstats.pcs[i] == pc){
  75. ainc(&waitstats.ns[i]);
  76. if(w > waitstats.wait[i])
  77. waitstats.wait[i] = w; /* race but ok */
  78. waitstats.total[i] += w;
  79. unlock(&waitstatslk);
  80. return;
  81. }
  82. for(i = 0; i < NWstats; i++)
  83. if(waitstats.pcs[i] == 0){
  84. waitstats.ns[i] = 1;
  85. waitstats.type[i] = type;
  86. waitstats.wait[i] = w;
  87. waitstats.total[i] = w;
  88. mfence();
  89. waitstats.pcs[i] = pc;
  90. waitstats.npcs++;
  91. break;
  92. }
  93. unlock(&waitstatslk);
  94. }
  95. void
  96. lockloop(Lock *l, uintptr pc)
  97. {
  98. Proc *p;
  99. p = l->p;
  100. print("lock %#p loop key %#ux pc %#p held by pc %#p proc %d\n",
  101. l, l->key, pc, l->pc, p ? p->pid : 0);
  102. dumpaproc(up);
  103. if(p != nil)
  104. dumpaproc(p);
  105. }
  106. int
  107. lock(Lock *l)
  108. {
  109. int i;
  110. uintptr pc;
  111. uint64_t t0;
  112. pc = getcallerpc(&l);
  113. lockstats.locks++;
  114. if(up)
  115. ainc(&up->nlocks); /* prevent being scheded */
  116. if(TAS(&l->key) == 0){
  117. if(up)
  118. up->lastlock = l;
  119. l->pc = pc;
  120. l->p = up;
  121. l->isilock = 0;
  122. if(LOCKCYCLES)
  123. cycles(&l->lockcycles);
  124. return 0;
  125. }
  126. if(up)
  127. adec(&up->nlocks);
  128. cycles(&t0);
  129. lockstats.glare++;
  130. for(;;){
  131. lockstats.inglare++;
  132. i = 0;
  133. while(l->key){
  134. if(sys->nmach < 2 && up && up->edf && (up->edf->flags & Admitted)){
  135. /*
  136. * Priority inversion, yield on a uniprocessor; on a
  137. * multiprocessor, the other processor will unlock
  138. */
  139. print("inversion %#p pc %#p proc %d held by pc %#p proc %d\n",
  140. l, pc, up ? up->pid : 0, l->pc, l->p ? l->p->pid : 0);
  141. up->edf->d = todget(nil); /* yield to process with lock */
  142. }
  143. if(i++ > 100000000){
  144. i = 0;
  145. lockloop(l, pc);
  146. }
  147. }
  148. if(up)
  149. ainc(&up->nlocks);
  150. if(TAS(&l->key) == 0){
  151. if(up)
  152. up->lastlock = l;
  153. l->pc = pc;
  154. l->p = up;
  155. l->isilock = 0;
  156. if(LOCKCYCLES)
  157. cycles(&l->lockcycles);
  158. if(l != &waitstatslk)
  159. addwaitstat(pc, t0, WSlock);
  160. return 1;
  161. }
  162. if(up)
  163. adec(&up->nlocks);
  164. }
  165. }
  166. void
  167. ilock(Lock *l)
  168. {
  169. Mpl pl;
  170. uintptr pc;
  171. uint64_t t0;
  172. pc = getcallerpc(&l);
  173. lockstats.locks++;
  174. pl = splhi();
  175. if(TAS(&l->key) != 0){
  176. cycles(&t0);
  177. lockstats.glare++;
  178. /*
  179. * Cannot also check l->pc, l->m, or l->isilock here
  180. * because they might just not be set yet, or
  181. * (for pc and m) the lock might have just been unlocked.
  182. */
  183. for(;;){
  184. lockstats.inglare++;
  185. splx(pl);
  186. while(l->key)
  187. ;
  188. pl = splhi();
  189. if(TAS(&l->key) == 0){
  190. if(l != &waitstatslk)
  191. addwaitstat(pc, t0, WSlock);
  192. goto acquire;
  193. }
  194. }
  195. }
  196. acquire:
  197. m->ilockdepth++;
  198. if(up)
  199. up->lastilock = l;
  200. l->pl = pl;
  201. l->pc = pc;
  202. l->p = up;
  203. l->isilock = 1;
  204. l->m = m;
  205. if(LOCKCYCLES)
  206. cycles(&l->lockcycles);
  207. }
  208. int
  209. canlock(Lock *l)
  210. {
  211. if(up)
  212. ainc(&up->nlocks);
  213. if(TAS(&l->key)){
  214. if(up)
  215. adec(&up->nlocks);
  216. return 0;
  217. }
  218. if(up)
  219. up->lastlock = l;
  220. l->pc = getcallerpc(&l);
  221. l->p = up;
  222. l->m = m;
  223. l->isilock = 0;
  224. if(LOCKCYCLES)
  225. cycles(&l->lockcycles);
  226. return 1;
  227. }
  228. void
  229. unlock(Lock *l)
  230. {
  231. uint64_t x;
  232. if(LOCKCYCLES){
  233. cycles(&x);
  234. l->lockcycles = x - l->lockcycles;
  235. if(l->lockcycles > maxlockcycles){
  236. maxlockcycles = l->lockcycles;
  237. maxlockpc = l->pc;
  238. }
  239. }
  240. if(l->key == 0)
  241. print("unlock: not locked: pc %#p\n", getcallerpc(&l));
  242. if(l->isilock)
  243. print("unlock of ilock: pc %#p, held by %#p\n", getcallerpc(&l), l->pc);
  244. if(l->p != up)
  245. print("unlock: up changed: pc %#p, acquired at pc %#p, lock p %#p, unlock up %#p\n", getcallerpc(&l), l->pc, l->p, up);
  246. l->m = nil;
  247. l->key = 0;
  248. coherence();
  249. if(up && adec(&up->nlocks) == 0 && up->delaysched && islo()){
  250. /*
  251. * Call sched if the need arose while locks were held
  252. * But, don't do it from interrupt routines, hence the islo() test
  253. */
  254. sched();
  255. }
  256. }
  257. void
  258. iunlock(Lock *l)
  259. {
  260. Mpl pl;
  261. uint64_t x;
  262. if(LOCKCYCLES){
  263. cycles(&x);
  264. l->lockcycles = x - l->lockcycles;
  265. if(l->lockcycles > maxilockcycles){
  266. maxilockcycles = l->lockcycles;
  267. maxilockpc = l->pc;
  268. }
  269. }
  270. if(l->key == 0)
  271. print("iunlock: not locked: pc %#p\n", getcallerpc(&l));
  272. if(!l->isilock)
  273. print("iunlock of lock: pc %#p, held by %#p\n", getcallerpc(&l), l->pc);
  274. if(islo())
  275. print("iunlock while lo: pc %#p, held by %#p\n", getcallerpc(&l), l->pc);
  276. if(l->m != m){
  277. print("iunlock by cpu%d, locked by cpu%d: pc %#p, held by %#p\n",
  278. m->machno, l->m->machno, getcallerpc(&l), l->pc);
  279. }
  280. pl = l->pl;
  281. l->m = nil;
  282. l->key = 0;
  283. coherence();
  284. m->ilockdepth--;
  285. if(up)
  286. up->lastilock = nil;
  287. splx(pl);
  288. }
  289. void
  290. portmwait(void *value)
  291. {
  292. while (*(void**)value == nil)
  293. ;
  294. }
  295. void (*mwait)(void *) = portmwait;