qlock.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  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: %lux: ilockdepth %d\n", getcallerpc(&q), m->ilockdepth);
  20. if(up != nil && up->nlocks.ref)
  21. print("qlock: %lux: 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. p = q->head;
  65. if(p){
  66. q->head = p->qnext;
  67. if(q->head == 0)
  68. q->tail = 0;
  69. unlock(&q->use);
  70. ready(p);
  71. return;
  72. }
  73. q->locked = 0;
  74. unlock(&q->use);
  75. }
  76. void
  77. rlock(RWlock *q)
  78. {
  79. Proc *p;
  80. lock(&q->use);
  81. rwstats.rlock++;
  82. if(q->writer == 0 && q->head == nil){
  83. /* no writer, go for it */
  84. q->readers++;
  85. unlock(&q->use);
  86. return;
  87. }
  88. rwstats.rlockq++;
  89. p = q->tail;
  90. if(up == nil)
  91. panic("rlock");
  92. if(p == 0)
  93. q->head = up;
  94. else
  95. p->qnext = up;
  96. q->tail = up;
  97. up->qnext = 0;
  98. up->state = QueueingR;
  99. unlock(&q->use);
  100. sched();
  101. }
  102. void
  103. runlock(RWlock *q)
  104. {
  105. Proc *p;
  106. lock(&q->use);
  107. p = q->head;
  108. if(--(q->readers) > 0 || p == nil){
  109. unlock(&q->use);
  110. return;
  111. }
  112. /* start waiting writer */
  113. if(p->state != QueueingW)
  114. panic("runlock");
  115. q->head = p->qnext;
  116. if(q->head == 0)
  117. q->tail = 0;
  118. q->writer = 1;
  119. unlock(&q->use);
  120. ready(p);
  121. }
  122. void
  123. wlock(RWlock *q)
  124. {
  125. Proc *p;
  126. lock(&q->use);
  127. rwstats.wlock++;
  128. if(q->readers == 0 && q->writer == 0){
  129. /* noone waiting, go for it */
  130. q->wpc = getcallerpc(&q);
  131. q->wproc = up;
  132. q->writer = 1;
  133. unlock(&q->use);
  134. return;
  135. }
  136. /* wait */
  137. rwstats.wlockq++;
  138. p = q->tail;
  139. if(up == nil)
  140. panic("wlock");
  141. if(p == nil)
  142. q->head = up;
  143. else
  144. p->qnext = up;
  145. q->tail = up;
  146. up->qnext = 0;
  147. up->state = QueueingW;
  148. unlock(&q->use);
  149. sched();
  150. }
  151. void
  152. wunlock(RWlock *q)
  153. {
  154. Proc *p;
  155. lock(&q->use);
  156. p = q->head;
  157. if(p == nil){
  158. q->writer = 0;
  159. unlock(&q->use);
  160. return;
  161. }
  162. if(p->state == QueueingW){
  163. /* start waiting writer */
  164. q->head = p->qnext;
  165. if(q->head == nil)
  166. q->tail = nil;
  167. unlock(&q->use);
  168. ready(p);
  169. return;
  170. }
  171. if(p->state != QueueingR)
  172. panic("wunlock");
  173. /* waken waiting readers */
  174. while(q->head != nil && q->head->state == QueueingR){
  175. p = q->head;
  176. q->head = p->qnext;
  177. q->readers++;
  178. ready(p);
  179. }
  180. if(q->head == nil)
  181. q->tail = nil;
  182. q->writer = 0;
  183. unlock(&q->use);
  184. }
  185. /* same as rlock but punts if there are any writers waiting */
  186. int
  187. canrlock(RWlock *q)
  188. {
  189. lock(&q->use);
  190. rwstats.rlock++;
  191. if(q->writer == 0 && q->head == nil){
  192. /* no writer, go for it */
  193. q->readers++;
  194. unlock(&q->use);
  195. return 1;
  196. }
  197. unlock(&q->use);
  198. return 0;
  199. }