Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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