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/edf.h"
8
9 uvlong maxlockcycles;
10 uvlong maxilockcycles;
11 ulong maxlockpc;
12 ulong maxilockpc;
13
14 struct
15 {
16 ulong locks;
17 ulong glare;
18 ulong inglare;
19 } lockstats;
20
21 static void
dumplockmem(char * tag,Lock * l)22 dumplockmem(char *tag, Lock *l)
23 {
24 uchar *cp;
25 int i;
26
27 iprint("%s: ", tag);
28 cp = (uchar*)l;
29 for(i = 0; i < 64; i++)
30 iprint("%2.2ux ", cp[i]);
31 iprint("\n");
32 }
33
34 void
lockloop(Lock * l,uintptr pc)35 lockloop(Lock *l, uintptr pc)
36 {
37 Proc *p;
38
39 p = l->p;
40 print("lock %#p loop key %#ux pc %#p held by pc %#p proc %d\n",
41 l, l->key, pc, l->pc, p ? p->pid : 0);
42 dumpaproc(up);
43 if(p != nil)
44 dumpaproc(p);
45 }
46
47 int
lock(Lock * l)48 lock(Lock *l)
49 {
50 int i;
51 uintptr pc;
52
53 pc = getcallerpc(&l);
54
55 lockstats.locks++;
56 if(up)
57 ainc(&up->nlocks); /* prevent being scheded */
58 if(TAS(&l->key) == 0){
59 if(up)
60 up->lastlock = l;
61 l->pc = pc;
62 l->p = up;
63 l->isilock = 0;
64 l->m = m;
65 #ifdef LOCKCYCLES
66 cycles(&l->lockcycles);
67 #endif
68 return 0;
69 }
70 if(up)
71 adec(&up->nlocks);
72
73 lockstats.glare++;
74 for(;;){
75 lockstats.inglare++;
76 i = 0;
77 while(l->key){
78 if(sys->nonline < 2 && up && up->edf && (up->edf->flags & Admitted)){
79 /*
80 * Priority inversion, yield on a uniprocessor; on a
81 * multiprocessor, the other processor will unlock
82 */
83 print("inversion %#p pc %#p proc %d held by pc %#p proc %d\n",
84 l, pc, up ? up->pid : 0, l->pc, l->p ? l->p->pid : 0);
85 up->edf->d = todget(nil); /* yield to process with lock */
86 }
87 if(i++ > 100000000){
88 i = 0;
89 lockloop(l, pc);
90 }
91 }
92 if(up)
93 ainc(&up->nlocks);
94 if(TAS(&l->key) == 0){
95 if(up)
96 up->lastlock = l;
97 l->pc = pc;
98 l->p = up;
99 l->isilock = 0;
100 l->m = m;
101 #ifdef LOCKCYCLES
102 cycles(&l->lockcycles);
103 #endif
104 return 1;
105 }
106 if(up)
107 adec(&up->nlocks);
108 }
109 }
110
111 void
ilock(Lock * l)112 ilock(Lock *l)
113 {
114 Mreg s;
115 uintptr pc;
116
117 pc = getcallerpc(&l);
118 lockstats.locks++;
119
120 s = splhi();
121 if(TAS(&l->key) != 0){
122 lockstats.glare++;
123 /*
124 * Cannot also check l->pc, l->m, or l->isilock here
125 * because they might just not be set yet, or
126 * (for pc and m) the lock might have just been unlocked.
127 */
128 for(;;){
129 lockstats.inglare++;
130 splx(s);
131 while(l->key)
132 ;
133 s = splhi();
134 if(TAS(&l->key) == 0)
135 goto acquire;
136 }
137 }
138 acquire:
139 m->ilockdepth++;
140 m->ilockpc = pc;
141 if(up)
142 up->lastilock = l;
143 l->sr = s;
144 l->pc = pc;
145 l->p = up;
146 l->isilock = 1;
147 l->m = m;
148 #ifdef LOCKCYCLES
149 cycles(&l->lockcycles);
150 #endif
151 }
152
153 int
canlock(Lock * l)154 canlock(Lock *l)
155 {
156 if(up)
157 ainc(&up->nlocks);
158 if(TAS(&l->key)){
159 if(up)
160 adec(&up->nlocks);
161 return 0;
162 }
163
164 if(up)
165 up->lastlock = l;
166 l->pc = getcallerpc(&l);
167 l->p = up;
168 l->m = m;
169 l->isilock = 0;
170 #ifdef LOCKCYCLES
171 cycles(&l->lockcycles);
172 #endif
173 return 1;
174 }
175
176 void
unlock(Lock * l)177 unlock(Lock *l)
178 {
179 #ifdef LOCKCYCLES
180 uvlong x;
181 cycles(&x);
182 l->lockcycles = x - l->lockcycles;
183 if(l->lockcycles > maxlockcycles){
184 maxlockcycles = l->lockcycles;
185 maxlockpc = l->pc;
186 }
187 #endif
188
189 if(l->key == 0)
190 print("unlock: not locked: pc %#p\n", getcallerpc(&l));
191 if(l->isilock)
192 print("unlock of ilock: pc %#p, held by %#p\n", getcallerpc(&l), l->pc);
193 if(l->p != up)
194 print("unlock: up changed: pc %#p, acquired at pc %#p, lock p %#p, unlock up %#p\n", getcallerpc(&l), l->pc, l->p, up);
195 l->m = nil;
196 l->key = 0;
197 coherence();
198
199 if(up && adec(&up->nlocks) == 0 && up->delaysched && islo()){
200 /*
201 * Call sched if the need arose while locks were held
202 * But, don't do it from interrupt routines, hence the islo() test
203 */
204 sched();
205 }
206 }
207
208 void
iunlock(Lock * l)209 iunlock(Lock *l)
210 {
211 Mreg s;
212
213 #ifdef LOCKCYCLES
214 uvlong x;
215 cycles(&x);
216 l->lockcycles = x - l->lockcycles;
217 if(l->lockcycles > maxilockcycles){
218 maxilockcycles = l->lockcycles;
219 maxilockpc = l->pc;
220 }
221 #endif
222
223 if(l->key == 0)
224 print("iunlock: not locked: pc %#p\n", getcallerpc(&l));
225 if(!l->isilock)
226 print("iunlock of lock: pc %#p, held by %#p\n", getcallerpc(&l), l->pc);
227 if(islo())
228 print("iunlock while lo: pc %#p, held by %#p\n", getcallerpc(&l), l->pc);
229 if(l->m != m){
230 print("iunlock by cpu%d, locked by cpu%d: pc %#p, held by %#p\n",
231 m->machno, l->m->machno, getcallerpc(&l), l->pc);
232 }
233
234 s = l->sr;
235 l->m = nil;
236 l->key = 0;
237 coherence();
238 m->ilockdepth--;
239 if(up)
240 up->lastilock = nil;
241 splx(s);
242 }
243