qlock.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  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 <trace.h>
  15. QLockstats qlockstats;
  16. static void
  17. lockstat(uintptr_t pc, uint64_t w)
  18. {
  19. addwaitstat(pc, w, WSqlock);
  20. }
  21. static void
  22. slockstat(uintptr_t pc, uint64_t w)
  23. {
  24. addwaitstat(pc, w, WSslock);
  25. }
  26. void
  27. qlock(QLock *q)
  28. {
  29. Mach *m = machp();
  30. Proc *p;
  31. uint64_t t0;
  32. cycles(&t0);
  33. if(m->ilockdepth != 0)
  34. print("qlock: %#p: ilockdepth %d", getcallerpc(&q), m->ilockdepth);
  35. if(m->externup != nil && m->externup->nlocks)
  36. print("qlock: %#p: nlocks %d", getcallerpc(&q), m->externup->nlocks);
  37. if(!canlock(&q->use)){
  38. lock(&q->use);
  39. slockstat(getcallerpc(&q), t0);
  40. }
  41. qlockstats.qlock++;
  42. if(!q->locked) {
  43. q->locked = 1;
  44. q->pc = getcallerpc(&q);
  45. unlock(&q->use);
  46. return;
  47. }
  48. if(m->externup == nil)
  49. panic("qlock");
  50. qlockstats.qlockq++;
  51. p = q->tail;
  52. if(p == 0)
  53. q->head = m->externup;
  54. else
  55. p->qnext = m->externup;
  56. q->tail = m->externup;
  57. m->externup->qnext = 0;
  58. m->externup->state = Queueing;
  59. m->externup->qpc = getcallerpc(&q);
  60. if(m->externup->trace)
  61. proctrace(m->externup, SLock, 0);
  62. unlock(&q->use);
  63. sched();
  64. lockstat(getcallerpc(&q), t0);
  65. }
  66. int
  67. canqlock(QLock *q)
  68. {
  69. if(!canlock(&q->use))
  70. return 0;
  71. if(q->locked){
  72. unlock(&q->use);
  73. return 0;
  74. }
  75. q->locked = 1;
  76. q->pc = getcallerpc(&q);
  77. unlock(&q->use);
  78. return 1;
  79. }
  80. void
  81. qunlock(QLock *q)
  82. {
  83. Proc *p;
  84. uint64_t t0;
  85. if(!canlock(&q->use)){
  86. cycles(&t0);
  87. lock(&q->use);
  88. slockstat(getcallerpc(&q), t0);
  89. }
  90. if (q->locked == 0)
  91. print("qunlock called with qlock not held, from %#p\n",
  92. getcallerpc(&q));
  93. p = q->head;
  94. if(p){
  95. q->head = p->qnext;
  96. if(q->head == 0)
  97. q->tail = 0;
  98. unlock(&q->use);
  99. q->pc = p->qpc;
  100. ready(p);
  101. return;
  102. }
  103. q->locked = 0;
  104. q->pc = 0;
  105. unlock(&q->use);
  106. }
  107. void
  108. rlock(RWlock *q)
  109. {
  110. Mach *m = machp();
  111. Proc *p;
  112. uint64_t t0;
  113. cycles(&t0);
  114. if(!canlock(&q->use)){
  115. lock(&q->use);
  116. slockstat(getcallerpc(&q), t0);
  117. }
  118. qlockstats.rlock++;
  119. if(q->writer == 0 && q->head == nil){
  120. /* no writer, go for it */
  121. q->readers++;
  122. unlock(&q->use);
  123. return;
  124. }
  125. qlockstats.rlockq++;
  126. p = q->tail;
  127. if(m->externup == nil)
  128. panic("rlock");
  129. if(p == 0)
  130. q->head = m->externup;
  131. else
  132. p->qnext = m->externup;
  133. q->tail = m->externup;
  134. m->externup->qnext = 0;
  135. m->externup->state = QueueingR;
  136. if(m->externup->trace)
  137. proctrace(m->externup, SLock, 0);
  138. unlock(&q->use);
  139. sched();
  140. lockstat(getcallerpc(&q), t0);
  141. }
  142. void
  143. runlock(RWlock *q)
  144. {
  145. Proc *p;
  146. uint64_t t0;
  147. if(!canlock(&q->use)){
  148. cycles(&t0);
  149. lock(&q->use);
  150. slockstat(getcallerpc(&q), t0);
  151. }
  152. p = q->head;
  153. if(--(q->readers) > 0 || p == nil){
  154. unlock(&q->use);
  155. return;
  156. }
  157. /* start waiting writer */
  158. if(p->state != QueueingW)
  159. panic("runlock");
  160. q->head = p->qnext;
  161. if(q->head == 0)
  162. q->tail = 0;
  163. q->writer = 1;
  164. unlock(&q->use);
  165. ready(p);
  166. }
  167. void
  168. wlock(RWlock *q)
  169. {
  170. Mach *m = machp();
  171. Proc *p;
  172. uint64_t t0;
  173. cycles(&t0);
  174. if(!canlock(&q->use)){
  175. lock(&q->use);
  176. slockstat(getcallerpc(&q), t0);
  177. }
  178. qlockstats.wlock++;
  179. if(q->readers == 0 && q->writer == 0){
  180. /* noone waiting, go for it */
  181. q->wpc = getcallerpc(&q);
  182. q->wproc = m->externup;
  183. q->writer = 1;
  184. unlock(&q->use);
  185. return;
  186. }
  187. /* wait */
  188. qlockstats.wlockq++;
  189. p = q->tail;
  190. if(m->externup == nil)
  191. panic("wlock");
  192. if(p == nil)
  193. q->head = m->externup;
  194. else
  195. p->qnext = m->externup;
  196. q->tail = m->externup;
  197. m->externup->qnext = 0;
  198. m->externup->state = QueueingW;
  199. if(m->externup->trace)
  200. proctrace(m->externup, SLock, 0);
  201. unlock(&q->use);
  202. sched();
  203. lockstat(getcallerpc(&q), t0);
  204. }
  205. void
  206. wunlock(RWlock *q)
  207. {
  208. Proc *p;
  209. uint64_t t0;
  210. if(!canlock(&q->use)){
  211. cycles(&t0);
  212. lock(&q->use);
  213. slockstat(getcallerpc(&q), t0);
  214. }
  215. p = q->head;
  216. if(p == nil){
  217. q->writer = 0;
  218. unlock(&q->use);
  219. return;
  220. }
  221. if(p->state == QueueingW){
  222. /* start waiting writer */
  223. q->head = p->qnext;
  224. if(q->head == nil)
  225. q->tail = nil;
  226. unlock(&q->use);
  227. ready(p);
  228. return;
  229. }
  230. if(p->state != QueueingR)
  231. panic("wunlock");
  232. /* waken waiting readers */
  233. while(q->head != nil && q->head->state == QueueingR){
  234. p = q->head;
  235. q->head = p->qnext;
  236. q->readers++;
  237. ready(p);
  238. }
  239. if(q->head == nil)
  240. q->tail = nil;
  241. q->writer = 0;
  242. unlock(&q->use);
  243. }
  244. /* same as rlock but punts if there are any writers waiting */
  245. int
  246. canrlock(RWlock *q)
  247. {
  248. uint64_t t0;
  249. if(!canlock(&q->use)){
  250. cycles(&t0);
  251. lock(&q->use);
  252. slockstat(getcallerpc(&q), t0);
  253. }
  254. qlockstats.rlock++;
  255. if(q->writer == 0 && q->head == nil){
  256. /* no writer, go for it */
  257. q->readers++;
  258. unlock(&q->use);
  259. return 1;
  260. }
  261. unlock(&q->use);
  262. return 0;
  263. }