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