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