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