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