qlock.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. #include <u.h>
  2. #include <libc.h>
  3. static struct {
  4. QLp *p;
  5. QLp x[1024];
  6. } ql = {
  7. ql.x
  8. };
  9. enum
  10. {
  11. Queuing,
  12. QueuingR,
  13. QueuingW,
  14. Sleeping,
  15. };
  16. static void* (*_rendezvousp)(void*, void*) = rendezvous;
  17. /* this gets called by the thread library ONLY to get us to use its rendezvous */
  18. void
  19. _qlockinit(void* (*r)(void*, void*))
  20. {
  21. _rendezvousp = r;
  22. }
  23. /* find a free shared memory location to queue ourselves in */
  24. static QLp*
  25. getqlp(void)
  26. {
  27. QLp *p, *op;
  28. op = ql.p;
  29. for(p = op+1; ; p++){
  30. if(p == &ql.x[nelem(ql.x)])
  31. p = ql.x;
  32. if(p == op)
  33. abort();
  34. if(_tas(&(p->inuse)) == 0){
  35. ql.p = p;
  36. p->next = nil;
  37. break;
  38. }
  39. }
  40. return p;
  41. }
  42. void
  43. qlock(QLock *q)
  44. {
  45. QLp *p, *mp;
  46. lock(&q->lock);
  47. if(!q->locked){
  48. q->locked = 1;
  49. unlock(&q->lock);
  50. return;
  51. }
  52. /* chain into waiting list */
  53. mp = getqlp();
  54. p = q->tail;
  55. if(p == nil)
  56. q->head = mp;
  57. else
  58. p->next = mp;
  59. q->tail = mp;
  60. mp->state = Queuing;
  61. unlock(&q->lock);
  62. /* wait */
  63. while((*_rendezvousp)(mp, (void*)1) == (void*)~0)
  64. ;
  65. mp->inuse = 0;
  66. }
  67. void
  68. qunlock(QLock *q)
  69. {
  70. QLp *p;
  71. lock(&q->lock);
  72. if (q->locked == 0)
  73. fprint(2, "qunlock called with qlock not held, from %#p\n",
  74. getcallerpc(&q));
  75. p = q->head;
  76. if(p != nil){
  77. /* wakeup head waiting process */
  78. q->head = p->next;
  79. if(q->head == nil)
  80. q->tail = nil;
  81. unlock(&q->lock);
  82. while((*_rendezvousp)(p, (void*)0x12345) == (void*)~0)
  83. ;
  84. return;
  85. }
  86. q->locked = 0;
  87. unlock(&q->lock);
  88. }
  89. int
  90. canqlock(QLock *q)
  91. {
  92. if(!canlock(&q->lock))
  93. return 0;
  94. if(!q->locked){
  95. q->locked = 1;
  96. unlock(&q->lock);
  97. return 1;
  98. }
  99. unlock(&q->lock);
  100. return 0;
  101. }
  102. void
  103. rlock(RWLock *q)
  104. {
  105. QLp *p, *mp;
  106. lock(&q->lock);
  107. if(q->writer == 0 && q->head == nil){
  108. /* no writer, go for it */
  109. q->readers++;
  110. unlock(&q->lock);
  111. return;
  112. }
  113. mp = getqlp();
  114. p = q->tail;
  115. if(p == 0)
  116. q->head = mp;
  117. else
  118. p->next = mp;
  119. q->tail = mp;
  120. mp->next = nil;
  121. mp->state = QueuingR;
  122. unlock(&q->lock);
  123. /* wait in kernel */
  124. while((*_rendezvousp)(mp, (void*)1) == (void*)~0)
  125. ;
  126. mp->inuse = 0;
  127. }
  128. int
  129. canrlock(RWLock *q)
  130. {
  131. lock(&q->lock);
  132. if (q->writer == 0 && q->head == nil) {
  133. /* no writer; go for it */
  134. q->readers++;
  135. unlock(&q->lock);
  136. return 1;
  137. }
  138. unlock(&q->lock);
  139. return 0;
  140. }
  141. void
  142. runlock(RWLock *q)
  143. {
  144. QLp *p;
  145. lock(&q->lock);
  146. if(q->readers <= 0)
  147. abort();
  148. p = q->head;
  149. if(--(q->readers) > 0 || p == nil){
  150. unlock(&q->lock);
  151. return;
  152. }
  153. /* start waiting writer */
  154. if(p->state != QueuingW)
  155. abort();
  156. q->head = p->next;
  157. if(q->head == 0)
  158. q->tail = 0;
  159. q->writer = 1;
  160. unlock(&q->lock);
  161. /* wakeup waiter */
  162. while((*_rendezvousp)(p, 0) == (void*)~0)
  163. ;
  164. }
  165. void
  166. wlock(RWLock *q)
  167. {
  168. QLp *p, *mp;
  169. lock(&q->lock);
  170. if(q->readers == 0 && q->writer == 0){
  171. /* noone waiting, go for it */
  172. q->writer = 1;
  173. unlock(&q->lock);
  174. return;
  175. }
  176. /* wait */
  177. p = q->tail;
  178. mp = getqlp();
  179. if(p == nil)
  180. q->head = mp;
  181. else
  182. p->next = mp;
  183. q->tail = mp;
  184. mp->next = nil;
  185. mp->state = QueuingW;
  186. unlock(&q->lock);
  187. /* wait in kernel */
  188. while((*_rendezvousp)(mp, (void*)1) == (void*)~0)
  189. ;
  190. mp->inuse = 0;
  191. }
  192. int
  193. canwlock(RWLock *q)
  194. {
  195. lock(&q->lock);
  196. if (q->readers == 0 && q->writer == 0) {
  197. /* no one waiting; go for it */
  198. q->writer = 1;
  199. unlock(&q->lock);
  200. return 1;
  201. }
  202. unlock(&q->lock);
  203. return 0;
  204. }
  205. void
  206. wunlock(RWLock *q)
  207. {
  208. QLp *p;
  209. lock(&q->lock);
  210. if(q->writer == 0)
  211. abort();
  212. p = q->head;
  213. if(p == nil){
  214. q->writer = 0;
  215. unlock(&q->lock);
  216. return;
  217. }
  218. if(p->state == QueuingW){
  219. /* start waiting writer */
  220. q->head = p->next;
  221. if(q->head == nil)
  222. q->tail = nil;
  223. unlock(&q->lock);
  224. while((*_rendezvousp)(p, 0) == (void*)~0)
  225. ;
  226. return;
  227. }
  228. if(p->state != QueuingR)
  229. abort();
  230. /* wake waiting readers */
  231. while(q->head != nil && q->head->state == QueuingR){
  232. p = q->head;
  233. q->head = p->next;
  234. q->readers++;
  235. while((*_rendezvousp)(p, 0) == (void*)~0)
  236. ;
  237. }
  238. if(q->head == nil)
  239. q->tail = nil;
  240. q->writer = 0;
  241. unlock(&q->lock);
  242. }
  243. void
  244. rsleep(Rendez *r)
  245. {
  246. QLp *t, *me;
  247. if(!r->l)
  248. abort();
  249. lock(&r->l->lock);
  250. /* we should hold the qlock */
  251. if(!r->l->locked)
  252. abort();
  253. /* add ourselves to the wait list */
  254. me = getqlp();
  255. me->state = Sleeping;
  256. if(r->head == nil)
  257. r->head = me;
  258. else
  259. r->tail->next = me;
  260. me->next = nil;
  261. r->tail = me;
  262. /* pass the qlock to the next guy */
  263. t = r->l->head;
  264. if(t){
  265. r->l->head = t->next;
  266. if(r->l->head == nil)
  267. r->l->tail = nil;
  268. unlock(&r->l->lock);
  269. while((*_rendezvousp)(t, (void*)0x12345) == (void*)~0)
  270. ;
  271. }else{
  272. r->l->locked = 0;
  273. unlock(&r->l->lock);
  274. }
  275. /* wait for a wakeup */
  276. while((*_rendezvousp)(me, (void*)1) == (void*)~0)
  277. ;
  278. me->inuse = 0;
  279. }
  280. int
  281. rwakeup(Rendez *r)
  282. {
  283. QLp *t;
  284. /*
  285. * take off wait and put on front of queue
  286. * put on front so guys that have been waiting will not get starved
  287. */
  288. if(!r->l)
  289. abort();
  290. lock(&r->l->lock);
  291. if(!r->l->locked)
  292. abort();
  293. t = r->head;
  294. if(t == nil){
  295. unlock(&r->l->lock);
  296. return 0;
  297. }
  298. r->head = t->next;
  299. if(r->head == nil)
  300. r->tail = nil;
  301. t->next = r->l->head;
  302. r->l->head = t;
  303. if(r->l->tail == nil)
  304. r->l->tail = t;
  305. t->state = Queuing;
  306. unlock(&r->l->lock);
  307. return 1;
  308. }
  309. int
  310. rwakeupall(Rendez *r)
  311. {
  312. int i;
  313. for(i=0; rwakeup(r); i++)
  314. ;
  315. return i;
  316. }