qlock.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. struct {
  7. ulong rlock;
  8. ulong rlockq;
  9. ulong wlock;
  10. ulong wlockq;
  11. ulong qlock;
  12. ulong qlockq;
  13. } rwstats;
  14. void
  15. qlock(QLock *q)
  16. {
  17. Proc *p;
  18. if(m->ilockdepth != 0)
  19. print("qlock: %#p: ilockdepth %d\n", getcallerpc(&q), m->ilockdepth);
  20. if(up != nil && up->nlocks.ref)
  21. print("qlock: %#p: nlocks %lud\n", getcallerpc(&q), up->nlocks.ref);
  22. if(q->use.key == 0x55555555)
  23. panic("qlock: q %#p, key 5*\n", q);
  24. lock(&q->use);
  25. rwstats.qlock++;
  26. if(!q->locked) {
  27. q->locked = 1;
  28. unlock(&q->use);
  29. return;
  30. }
  31. if(up == 0)
  32. panic("qlock");
  33. rwstats.qlockq++;
  34. p = q->tail;
  35. if(p == 0)
  36. q->head = up;
  37. else
  38. p->qnext = up;
  39. q->tail = up;
  40. up->qnext = 0;
  41. up->state = Queueing;
  42. up->qpc = getcallerpc(&q);
  43. unlock(&q->use);
  44. sched();
  45. }
  46. int
  47. canqlock(QLock *q)
  48. {
  49. if(!canlock(&q->use))
  50. return 0;
  51. if(q->locked){
  52. unlock(&q->use);
  53. return 0;
  54. }
  55. q->locked = 1;
  56. unlock(&q->use);
  57. return 1;
  58. }
  59. void
  60. qunlock(QLock *q)
  61. {
  62. Proc *p;
  63. lock(&q->use);
  64. if (q->locked == 0)
  65. print("qunlock called with qlock not held, from %#p\n",
  66. getcallerpc(&q));
  67. p = q->head;
  68. if(p){
  69. q->head = p->qnext;
  70. if(q->head == 0)
  71. q->tail = 0;
  72. unlock(&q->use);
  73. ready(p);
  74. return;
  75. }
  76. q->locked = 0;
  77. unlock(&q->use);
  78. }
  79. void
  80. rlock(RWlock *q)
  81. {
  82. Proc *p;
  83. lock(&q->use);
  84. rwstats.rlock++;
  85. if(q->writer == 0 && q->head == nil){
  86. /* no writer, go for it */
  87. q->readers++;
  88. unlock(&q->use);
  89. return;
  90. }
  91. rwstats.rlockq++;
  92. p = q->tail;
  93. if(up == nil)
  94. panic("rlock");
  95. if(p == 0)
  96. q->head = up;
  97. else
  98. p->qnext = up;
  99. q->tail = up;
  100. up->qnext = 0;
  101. up->state = QueueingR;
  102. unlock(&q->use);
  103. sched();
  104. }
  105. void
  106. runlock(RWlock *q)
  107. {
  108. Proc *p;
  109. lock(&q->use);
  110. p = q->head;
  111. if(--(q->readers) > 0 || p == nil){
  112. unlock(&q->use);
  113. return;
  114. }
  115. /* start waiting writer */
  116. if(p->state != QueueingW)
  117. panic("runlock");
  118. q->head = p->qnext;
  119. if(q->head == 0)
  120. q->tail = 0;
  121. q->writer = 1;
  122. unlock(&q->use);
  123. ready(p);
  124. }
  125. void
  126. wlock(RWlock *q)
  127. {
  128. Proc *p;
  129. lock(&q->use);
  130. rwstats.wlock++;
  131. if(q->readers == 0 && q->writer == 0){
  132. /* noone waiting, go for it */
  133. q->wpc = getcallerpc(&q);
  134. q->wproc = up;
  135. q->writer = 1;
  136. unlock(&q->use);
  137. return;
  138. }
  139. /* wait */
  140. rwstats.wlockq++;
  141. p = q->tail;
  142. if(up == nil)
  143. panic("wlock");
  144. if(p == nil)
  145. q->head = up;
  146. else
  147. p->qnext = up;
  148. q->tail = up;
  149. up->qnext = 0;
  150. up->state = QueueingW;
  151. unlock(&q->use);
  152. sched();
  153. }
  154. void
  155. wunlock(RWlock *q)
  156. {
  157. Proc *p;
  158. lock(&q->use);
  159. p = q->head;
  160. if(p == nil){
  161. q->writer = 0;
  162. unlock(&q->use);
  163. return;
  164. }
  165. if(p->state == QueueingW){
  166. /* start waiting writer */
  167. q->head = p->qnext;
  168. if(q->head == nil)
  169. q->tail = nil;
  170. unlock(&q->use);
  171. ready(p);
  172. return;
  173. }
  174. if(p->state != QueueingR)
  175. panic("wunlock");
  176. /* waken waiting readers */
  177. while(q->head != nil && q->head->state == QueueingR){
  178. p = q->head;
  179. q->head = p->qnext;
  180. q->readers++;
  181. ready(p);
  182. }
  183. if(q->head == nil)
  184. q->tail = nil;
  185. q->writer = 0;
  186. unlock(&q->use);
  187. }
  188. /* same as rlock but punts if there are any writers waiting */
  189. int
  190. canrlock(RWlock *q)
  191. {
  192. lock(&q->use);
  193. rwstats.rlock++;
  194. if(q->writer == 0 && q->head == nil){
  195. /* no writer, go for it */
  196. q->readers++;
  197. unlock(&q->use);
  198. return 1;
  199. }
  200. unlock(&q->use);
  201. return 0;
  202. }