FreeBSD/Linux Kernel Cross Reference
sys/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 }
Cache object: 4f93b74b8e1a214be37bf70c9d315712
|