xref: /plan9/sys/src/cmd/fossil/bwatch.c (revision 5e96a66c77eb9140492ca53f857cbbf108e128ed)
1*5e96a66cSDavid du Colombier #include "stdinc.h"
2*5e96a66cSDavid du Colombier #include "dat.h"
3*5e96a66cSDavid du Colombier #include "fns.h"
4*5e96a66cSDavid du Colombier #include "error.h"
5*5e96a66cSDavid du Colombier 
6*5e96a66cSDavid du Colombier /*
7*5e96a66cSDavid du Colombier  * Lock watcher.  Check that locking of blocks is always down.
8*5e96a66cSDavid du Colombier  *
9*5e96a66cSDavid du Colombier  * This is REALLY slow, and it won't work when the blocks aren't
10*5e96a66cSDavid du Colombier  * arranged in a tree (e.g., after the first snapshot).  But it's great
11*5e96a66cSDavid du Colombier  * for debugging.
12*5e96a66cSDavid du Colombier  */
13*5e96a66cSDavid du Colombier enum
14*5e96a66cSDavid du Colombier {
15*5e96a66cSDavid du Colombier 	MaxLock = 16,
16*5e96a66cSDavid du Colombier 	HashSize = 1009,
17*5e96a66cSDavid du Colombier };
18*5e96a66cSDavid du Colombier 
19*5e96a66cSDavid du Colombier /*
20*5e96a66cSDavid du Colombier  * Thread-specific watch state.
21*5e96a66cSDavid du Colombier  */
22*5e96a66cSDavid du Colombier typedef struct WThread WThread;
23*5e96a66cSDavid du Colombier struct WThread
24*5e96a66cSDavid du Colombier {
25*5e96a66cSDavid du Colombier 	Block *b[MaxLock];	/* blocks currently held */
26*5e96a66cSDavid du Colombier 	uint nb;
27*5e96a66cSDavid du Colombier 	uint pid;
28*5e96a66cSDavid du Colombier };
29*5e96a66cSDavid du Colombier 
30*5e96a66cSDavid du Colombier typedef struct WMap WMap;
31*5e96a66cSDavid du Colombier typedef struct WEntry WEntry;
32*5e96a66cSDavid du Colombier 
33*5e96a66cSDavid du Colombier struct WEntry
34*5e96a66cSDavid du Colombier {
35*5e96a66cSDavid du Colombier 	uchar c[VtScoreSize];
36*5e96a66cSDavid du Colombier 	uchar p[VtScoreSize];
37*5e96a66cSDavid du Colombier 	int off;
38*5e96a66cSDavid du Colombier 
39*5e96a66cSDavid du Colombier 	WEntry *cprev;
40*5e96a66cSDavid du Colombier 	WEntry *cnext;
41*5e96a66cSDavid du Colombier 	WEntry *pprev;
42*5e96a66cSDavid du Colombier 	WEntry *pnext;
43*5e96a66cSDavid du Colombier };
44*5e96a66cSDavid du Colombier 
45*5e96a66cSDavid du Colombier struct WMap
46*5e96a66cSDavid du Colombier {
47*5e96a66cSDavid du Colombier 	VtLock *lk;
48*5e96a66cSDavid du Colombier 
49*5e96a66cSDavid du Colombier 	WEntry *hchild[HashSize];
50*5e96a66cSDavid du Colombier 	WEntry *hparent[HashSize];
51*5e96a66cSDavid du Colombier };
52*5e96a66cSDavid du Colombier 
53*5e96a66cSDavid du Colombier static WMap map;
54*5e96a66cSDavid du Colombier static void **wp;
55*5e96a66cSDavid du Colombier static uint blockSize;
56*5e96a66cSDavid du Colombier static WEntry *pool;
57*5e96a66cSDavid du Colombier uint bwatchDisabled;
58*5e96a66cSDavid du Colombier 
59*5e96a66cSDavid du Colombier static uint
hash(uchar score[VtScoreSize])60*5e96a66cSDavid du Colombier hash(uchar score[VtScoreSize])
61*5e96a66cSDavid du Colombier {
62*5e96a66cSDavid du Colombier 	uint i, h;
63*5e96a66cSDavid du Colombier 
64*5e96a66cSDavid du Colombier 	h = 0;
65*5e96a66cSDavid du Colombier 	for(i=0; i<VtScoreSize; i++)
66*5e96a66cSDavid du Colombier 		h = h*37 + score[i];
67*5e96a66cSDavid du Colombier 	return h%HashSize;
68*5e96a66cSDavid du Colombier }
69*5e96a66cSDavid du Colombier 
70*5e96a66cSDavid du Colombier #include <pool.h>
71*5e96a66cSDavid du Colombier static void
freeWEntry(WEntry * e)72*5e96a66cSDavid du Colombier freeWEntry(WEntry *e)
73*5e96a66cSDavid du Colombier {
74*5e96a66cSDavid du Colombier 	memset(e, 0, sizeof(WEntry));
75*5e96a66cSDavid du Colombier 	e->pnext = pool;
76*5e96a66cSDavid du Colombier 	pool = e;
77*5e96a66cSDavid du Colombier }
78*5e96a66cSDavid du Colombier 
79*5e96a66cSDavid du Colombier static WEntry*
allocWEntry(void)80*5e96a66cSDavid du Colombier allocWEntry(void)
81*5e96a66cSDavid du Colombier {
82*5e96a66cSDavid du Colombier 	int i;
83*5e96a66cSDavid du Colombier 	WEntry *w;
84*5e96a66cSDavid du Colombier 
85*5e96a66cSDavid du Colombier 	w = pool;
86*5e96a66cSDavid du Colombier 	if(w == nil){
87*5e96a66cSDavid du Colombier 		w = vtMemAllocZ(1024*sizeof(WEntry));
88*5e96a66cSDavid du Colombier 		for(i=0; i<1024; i++)
89*5e96a66cSDavid du Colombier 			freeWEntry(&w[i]);
90*5e96a66cSDavid du Colombier 		w = pool;
91*5e96a66cSDavid du Colombier 	}
92*5e96a66cSDavid du Colombier 	pool = w->pnext;
93*5e96a66cSDavid du Colombier 	memset(w, 0, sizeof(WEntry));
94*5e96a66cSDavid du Colombier 	return w;
95*5e96a66cSDavid du Colombier }
96*5e96a66cSDavid du Colombier 
97*5e96a66cSDavid du Colombier /*
98*5e96a66cSDavid du Colombier  * remove all dependencies with score as a parent
99*5e96a66cSDavid du Colombier  */
100*5e96a66cSDavid du Colombier static void
_bwatchResetParent(uchar * score)101*5e96a66cSDavid du Colombier _bwatchResetParent(uchar *score)
102*5e96a66cSDavid du Colombier {
103*5e96a66cSDavid du Colombier 	WEntry *w, *next;
104*5e96a66cSDavid du Colombier 	uint h;
105*5e96a66cSDavid du Colombier 
106*5e96a66cSDavid du Colombier 	h = hash(score);
107*5e96a66cSDavid du Colombier 	for(w=map.hparent[h]; w; w=next){
108*5e96a66cSDavid du Colombier 		next = w->pnext;
109*5e96a66cSDavid du Colombier 		if(memcmp(w->p, score, VtScoreSize) == 0){
110*5e96a66cSDavid du Colombier 			if(w->pnext)
111*5e96a66cSDavid du Colombier 				w->pnext->pprev = w->pprev;
112*5e96a66cSDavid du Colombier 			if(w->pprev)
113*5e96a66cSDavid du Colombier 				w->pprev->pnext = w->pnext;
114*5e96a66cSDavid du Colombier 			else
115*5e96a66cSDavid du Colombier 				map.hparent[h] = w->pnext;
116*5e96a66cSDavid du Colombier 			if(w->cnext)
117*5e96a66cSDavid du Colombier 				w->cnext->cprev = w->cprev;
118*5e96a66cSDavid du Colombier 			if(w->cprev)
119*5e96a66cSDavid du Colombier 				w->cprev->cnext = w->cnext;
120*5e96a66cSDavid du Colombier 			else
121*5e96a66cSDavid du Colombier 				map.hchild[hash(w->c)] = w->cnext;
122*5e96a66cSDavid du Colombier 			freeWEntry(w);
123*5e96a66cSDavid du Colombier 		}
124*5e96a66cSDavid du Colombier 	}
125*5e96a66cSDavid du Colombier }
126*5e96a66cSDavid du Colombier /*
127*5e96a66cSDavid du Colombier  * and child
128*5e96a66cSDavid du Colombier  */
129*5e96a66cSDavid du Colombier static void
_bwatchResetChild(uchar * score)130*5e96a66cSDavid du Colombier _bwatchResetChild(uchar *score)
131*5e96a66cSDavid du Colombier {
132*5e96a66cSDavid du Colombier 	WEntry *w, *next;
133*5e96a66cSDavid du Colombier 	uint h;
134*5e96a66cSDavid du Colombier 
135*5e96a66cSDavid du Colombier 	h = hash(score);
136*5e96a66cSDavid du Colombier 	for(w=map.hchild[h]; w; w=next){
137*5e96a66cSDavid du Colombier 		next = w->cnext;
138*5e96a66cSDavid du Colombier 		if(memcmp(w->c, score, VtScoreSize) == 0){
139*5e96a66cSDavid du Colombier 			if(w->pnext)
140*5e96a66cSDavid du Colombier 				w->pnext->pprev = w->pprev;
141*5e96a66cSDavid du Colombier 			if(w->pprev)
142*5e96a66cSDavid du Colombier 				w->pprev->pnext = w->pnext;
143*5e96a66cSDavid du Colombier 			else
144*5e96a66cSDavid du Colombier 				map.hparent[hash(w->p)] = w->pnext;
145*5e96a66cSDavid du Colombier 			if(w->cnext)
146*5e96a66cSDavid du Colombier 				w->cnext->cprev = w->cprev;
147*5e96a66cSDavid du Colombier 			if(w->cprev)
148*5e96a66cSDavid du Colombier 				w->cprev->cnext = w->cnext;
149*5e96a66cSDavid du Colombier 			else
150*5e96a66cSDavid du Colombier 				map.hchild[h] = w->cnext;
151*5e96a66cSDavid du Colombier 			freeWEntry(w);
152*5e96a66cSDavid du Colombier 		}
153*5e96a66cSDavid du Colombier 	}
154*5e96a66cSDavid du Colombier }
155*5e96a66cSDavid du Colombier 
156*5e96a66cSDavid du Colombier static uchar*
parent(uchar c[VtScoreSize],int * off)157*5e96a66cSDavid du Colombier parent(uchar c[VtScoreSize], int *off)
158*5e96a66cSDavid du Colombier {
159*5e96a66cSDavid du Colombier 	WEntry *w;
160*5e96a66cSDavid du Colombier 	uint h;
161*5e96a66cSDavid du Colombier 
162*5e96a66cSDavid du Colombier 	h = hash(c);
163*5e96a66cSDavid du Colombier 	for(w=map.hchild[h]; w; w=w->cnext)
164*5e96a66cSDavid du Colombier 		if(memcmp(w->c, c, VtScoreSize) == 0){
165*5e96a66cSDavid du Colombier 			*off = w->off;
166*5e96a66cSDavid du Colombier 			return w->p;
167*5e96a66cSDavid du Colombier 		}
168*5e96a66cSDavid du Colombier 	return nil;
169*5e96a66cSDavid du Colombier }
170*5e96a66cSDavid du Colombier 
171*5e96a66cSDavid du Colombier static void
addChild(uchar p[VtEntrySize],uchar c[VtEntrySize],int off)172*5e96a66cSDavid du Colombier addChild(uchar p[VtEntrySize], uchar c[VtEntrySize], int off)
173*5e96a66cSDavid du Colombier {
174*5e96a66cSDavid du Colombier 	uint h;
175*5e96a66cSDavid du Colombier 	WEntry *w;
176*5e96a66cSDavid du Colombier 
177*5e96a66cSDavid du Colombier 	w = allocWEntry();
178*5e96a66cSDavid du Colombier 	memmove(w->p, p, VtScoreSize);
179*5e96a66cSDavid du Colombier 	memmove(w->c, c, VtScoreSize);
180*5e96a66cSDavid du Colombier 	w->off = off;
181*5e96a66cSDavid du Colombier 
182*5e96a66cSDavid du Colombier 	h = hash(p);
183*5e96a66cSDavid du Colombier 	w->pnext = map.hparent[h];
184*5e96a66cSDavid du Colombier 	if(w->pnext)
185*5e96a66cSDavid du Colombier 		w->pnext->pprev = w;
186*5e96a66cSDavid du Colombier 	map.hparent[h] = w;
187*5e96a66cSDavid du Colombier 
188*5e96a66cSDavid du Colombier 	h = hash(c);
189*5e96a66cSDavid du Colombier 	w->cnext = map.hchild[h];
190*5e96a66cSDavid du Colombier 	if(w->cnext)
191*5e96a66cSDavid du Colombier 		w->cnext->cprev = w;
192*5e96a66cSDavid du Colombier 	map.hchild[h] = w;
193*5e96a66cSDavid du Colombier }
194*5e96a66cSDavid du Colombier 
195*5e96a66cSDavid du Colombier void
bwatchReset(uchar score[VtScoreSize])196*5e96a66cSDavid du Colombier bwatchReset(uchar score[VtScoreSize])
197*5e96a66cSDavid du Colombier {
198*5e96a66cSDavid du Colombier 	vtLock(map.lk);
199*5e96a66cSDavid du Colombier 	_bwatchResetParent(score);
200*5e96a66cSDavid du Colombier 	_bwatchResetChild(score);
201*5e96a66cSDavid du Colombier 	vtUnlock(map.lk);
202*5e96a66cSDavid du Colombier }
203*5e96a66cSDavid du Colombier 
204*5e96a66cSDavid du Colombier void
bwatchInit(void)205*5e96a66cSDavid du Colombier bwatchInit(void)
206*5e96a66cSDavid du Colombier {
207*5e96a66cSDavid du Colombier 	map.lk = vtLockAlloc();
208*5e96a66cSDavid du Colombier 	wp = privalloc();
209*5e96a66cSDavid du Colombier 	*wp = nil;
210*5e96a66cSDavid du Colombier }
211*5e96a66cSDavid du Colombier 
212*5e96a66cSDavid du Colombier void
bwatchSetBlockSize(uint bs)213*5e96a66cSDavid du Colombier bwatchSetBlockSize(uint bs)
214*5e96a66cSDavid du Colombier {
215*5e96a66cSDavid du Colombier 	blockSize = bs;
216*5e96a66cSDavid du Colombier }
217*5e96a66cSDavid du Colombier 
218*5e96a66cSDavid du Colombier static WThread*
getWThread(void)219*5e96a66cSDavid du Colombier getWThread(void)
220*5e96a66cSDavid du Colombier {
221*5e96a66cSDavid du Colombier 	WThread *w;
222*5e96a66cSDavid du Colombier 
223*5e96a66cSDavid du Colombier 	w = *wp;
224*5e96a66cSDavid du Colombier 	if(w == nil || w->pid != getpid()){
225*5e96a66cSDavid du Colombier 		w = vtMemAllocZ(sizeof(WThread));
226*5e96a66cSDavid du Colombier 		*wp = w;
227*5e96a66cSDavid du Colombier 		w->pid = getpid();
228*5e96a66cSDavid du Colombier 	}
229*5e96a66cSDavid du Colombier 	return w;
230*5e96a66cSDavid du Colombier }
231*5e96a66cSDavid du Colombier 
232*5e96a66cSDavid du Colombier /*
233*5e96a66cSDavid du Colombier  * Derive dependencies from the contents of b.
234*5e96a66cSDavid du Colombier  */
235*5e96a66cSDavid du Colombier void
bwatchDependency(Block * b)236*5e96a66cSDavid du Colombier bwatchDependency(Block *b)
237*5e96a66cSDavid du Colombier {
238*5e96a66cSDavid du Colombier 	int i, epb, ppb;
239*5e96a66cSDavid du Colombier 	Entry e;
240*5e96a66cSDavid du Colombier 
241*5e96a66cSDavid du Colombier 	if(bwatchDisabled)
242*5e96a66cSDavid du Colombier 		return;
243*5e96a66cSDavid du Colombier 
244*5e96a66cSDavid du Colombier 	vtLock(map.lk);
245*5e96a66cSDavid du Colombier 	_bwatchResetParent(b->score);
246*5e96a66cSDavid du Colombier 
247*5e96a66cSDavid du Colombier 	switch(b->l.type){
248*5e96a66cSDavid du Colombier 	case BtData:
249*5e96a66cSDavid du Colombier 		break;
250*5e96a66cSDavid du Colombier 
251*5e96a66cSDavid du Colombier 	case BtDir:
252*5e96a66cSDavid du Colombier 		epb = blockSize / VtEntrySize;
253*5e96a66cSDavid du Colombier 		for(i=0; i<epb; i++){
254*5e96a66cSDavid du Colombier 			entryUnpack(&e, b->data, i);
255*5e96a66cSDavid du Colombier 			if(!(e.flags & VtEntryActive))
256*5e96a66cSDavid du Colombier 				continue;
257*5e96a66cSDavid du Colombier 			addChild(b->score, e.score, i);
258*5e96a66cSDavid du Colombier 		}
259*5e96a66cSDavid du Colombier 		break;
260*5e96a66cSDavid du Colombier 
261*5e96a66cSDavid du Colombier 	default:
262*5e96a66cSDavid du Colombier 		ppb = blockSize / VtScoreSize;
263*5e96a66cSDavid du Colombier 		for(i=0; i<ppb; i++)
264*5e96a66cSDavid du Colombier 			addChild(b->score, b->data+i*VtScoreSize, i);
265*5e96a66cSDavid du Colombier 		break;
266*5e96a66cSDavid du Colombier 	}
267*5e96a66cSDavid du Colombier 	vtUnlock(map.lk);
268*5e96a66cSDavid du Colombier }
269*5e96a66cSDavid du Colombier 
270*5e96a66cSDavid du Colombier static int
depth(uchar * s)271*5e96a66cSDavid du Colombier depth(uchar *s)
272*5e96a66cSDavid du Colombier {
273*5e96a66cSDavid du Colombier 	int d, x;
274*5e96a66cSDavid du Colombier 
275*5e96a66cSDavid du Colombier 	d = -1;
276*5e96a66cSDavid du Colombier 	while(s){
277*5e96a66cSDavid du Colombier 		d++;
278*5e96a66cSDavid du Colombier 		s = parent(s, &x);
279*5e96a66cSDavid du Colombier 	}
280*5e96a66cSDavid du Colombier 	return d;
281*5e96a66cSDavid du Colombier }
282*5e96a66cSDavid du Colombier 
283*5e96a66cSDavid du Colombier static int
lockConflicts(uchar xhave[VtScoreSize],uchar xwant[VtScoreSize])284*5e96a66cSDavid du Colombier lockConflicts(uchar xhave[VtScoreSize], uchar xwant[VtScoreSize])
285*5e96a66cSDavid du Colombier {
286*5e96a66cSDavid du Colombier 	uchar *have, *want;
287*5e96a66cSDavid du Colombier 	int havedepth, wantdepth, havepos, wantpos;
288*5e96a66cSDavid du Colombier 
289*5e96a66cSDavid du Colombier 	have = xhave;
290*5e96a66cSDavid du Colombier 	want = xwant;
291*5e96a66cSDavid du Colombier 
292*5e96a66cSDavid du Colombier 	havedepth = depth(have);
293*5e96a66cSDavid du Colombier 	wantdepth = depth(want);
294*5e96a66cSDavid du Colombier 
295*5e96a66cSDavid du Colombier 	/*
296*5e96a66cSDavid du Colombier 	 * walk one or the other up until they're both
297*5e96a66cSDavid du Colombier  	 * at the same level.
298*5e96a66cSDavid du Colombier 	 */
299*5e96a66cSDavid du Colombier 	havepos = -1;
300*5e96a66cSDavid du Colombier 	wantpos = -1;
301*5e96a66cSDavid du Colombier 	have = xhave;
302*5e96a66cSDavid du Colombier 	want = xwant;
303*5e96a66cSDavid du Colombier 	while(wantdepth > havedepth){
304*5e96a66cSDavid du Colombier 		wantdepth--;
305*5e96a66cSDavid du Colombier 		want = parent(want, &wantpos);
306*5e96a66cSDavid du Colombier 	}
307*5e96a66cSDavid du Colombier 	while(havedepth > wantdepth){
308*5e96a66cSDavid du Colombier 		havedepth--;
309*5e96a66cSDavid du Colombier 		have = parent(have, &havepos);
310*5e96a66cSDavid du Colombier 	}
311*5e96a66cSDavid du Colombier 
312*5e96a66cSDavid du Colombier 	/*
313*5e96a66cSDavid du Colombier 	 * walk them up simultaneously until we reach
314*5e96a66cSDavid du Colombier 	 * a common ancestor.
315*5e96a66cSDavid du Colombier 	 */
316*5e96a66cSDavid du Colombier 	while(have && want && memcmp(have, want, VtScoreSize) != 0){
317*5e96a66cSDavid du Colombier 		have = parent(have, &havepos);
318*5e96a66cSDavid du Colombier 		want = parent(want, &wantpos);
319*5e96a66cSDavid du Colombier 	}
320*5e96a66cSDavid du Colombier 
321*5e96a66cSDavid du Colombier 	/*
322*5e96a66cSDavid du Colombier 	 * not part of same tree.  happens mainly with
323*5e96a66cSDavid du Colombier 	 * newly allocated blocks.
324*5e96a66cSDavid du Colombier 	 */
325*5e96a66cSDavid du Colombier 	if(!have || !want)
326*5e96a66cSDavid du Colombier 		return 0;
327*5e96a66cSDavid du Colombier 
328*5e96a66cSDavid du Colombier 	/*
329*5e96a66cSDavid du Colombier 	 * never walked want: means we want to lock
330*5e96a66cSDavid du Colombier 	 * an ancestor of have.  no no.
331*5e96a66cSDavid du Colombier 	 */
332*5e96a66cSDavid du Colombier 	if(wantpos == -1)
333*5e96a66cSDavid du Colombier 		return 1;
334*5e96a66cSDavid du Colombier 
335*5e96a66cSDavid du Colombier 	/*
336*5e96a66cSDavid du Colombier 	 * never walked have: means we want to lock a
337*5e96a66cSDavid du Colombier 	 * child of have.  that's okay.
338*5e96a66cSDavid du Colombier 	 */
339*5e96a66cSDavid du Colombier 	if(havepos == -1)
340*5e96a66cSDavid du Colombier 		return 0;
341*5e96a66cSDavid du Colombier 
342*5e96a66cSDavid du Colombier 	/*
343*5e96a66cSDavid du Colombier 	 * walked both: they're from different places in the tree.
344*5e96a66cSDavid du Colombier 	 * require that the left one be locked before the right one.
345*5e96a66cSDavid du Colombier 	 * (this is questionable, but it puts a total order on the block tree).
346*5e96a66cSDavid du Colombier 	 */
347*5e96a66cSDavid du Colombier 	return havepos < wantpos;
348*5e96a66cSDavid du Colombier }
349*5e96a66cSDavid du Colombier 
350*5e96a66cSDavid du Colombier static void
stop(void)351*5e96a66cSDavid du Colombier stop(void)
352*5e96a66cSDavid du Colombier {
353*5e96a66cSDavid du Colombier 	int fd;
354*5e96a66cSDavid du Colombier 	char buf[32];
355*5e96a66cSDavid du Colombier 
356*5e96a66cSDavid du Colombier 	snprint(buf, sizeof buf, "#p/%d/ctl", getpid());
357*5e96a66cSDavid du Colombier 	fd = open(buf, OWRITE);
358*5e96a66cSDavid du Colombier 	write(fd, "stop", 4);
359*5e96a66cSDavid du Colombier 	close(fd);
360*5e96a66cSDavid du Colombier }
361*5e96a66cSDavid du Colombier 
362*5e96a66cSDavid du Colombier /*
363*5e96a66cSDavid du Colombier  * Check whether the calling thread can validly lock b.
364*5e96a66cSDavid du Colombier  * That is, check that the calling thread doesn't hold
365*5e96a66cSDavid du Colombier  * locks for any of b's children.
366*5e96a66cSDavid du Colombier  */
367*5e96a66cSDavid du Colombier void
bwatchLock(Block * b)368*5e96a66cSDavid du Colombier bwatchLock(Block *b)
369*5e96a66cSDavid du Colombier {
370*5e96a66cSDavid du Colombier 	int i;
371*5e96a66cSDavid du Colombier 	WThread *w;
372*5e96a66cSDavid du Colombier 
373*5e96a66cSDavid du Colombier 	if(bwatchDisabled)
374*5e96a66cSDavid du Colombier 		return;
375*5e96a66cSDavid du Colombier 
376*5e96a66cSDavid du Colombier 	if(b->part != PartData)
377*5e96a66cSDavid du Colombier 		return;
378*5e96a66cSDavid du Colombier 
379*5e96a66cSDavid du Colombier 	vtLock(map.lk);
380*5e96a66cSDavid du Colombier 	w = getWThread();
381*5e96a66cSDavid du Colombier 	for(i=0; i<w->nb; i++){
382*5e96a66cSDavid du Colombier 		if(lockConflicts(w->b[i]->score, b->score)){
383*5e96a66cSDavid du Colombier 			fprint(2, "%d: have block %V; shouldn't lock %V\n",
384*5e96a66cSDavid du Colombier 				w->pid, w->b[i]->score, b->score);
385*5e96a66cSDavid du Colombier 			stop();
386*5e96a66cSDavid du Colombier 		}
387*5e96a66cSDavid du Colombier 	}
388*5e96a66cSDavid du Colombier 	vtUnlock(map.lk);
389*5e96a66cSDavid du Colombier 	if(w->nb >= MaxLock){
390*5e96a66cSDavid du Colombier 		fprint(2, "%d: too many blocks held\n", w->pid);
391*5e96a66cSDavid du Colombier 		stop();
392*5e96a66cSDavid du Colombier 	}else
393*5e96a66cSDavid du Colombier 		w->b[w->nb++] = b;
394*5e96a66cSDavid du Colombier }
395*5e96a66cSDavid du Colombier 
396*5e96a66cSDavid du Colombier /*
397*5e96a66cSDavid du Colombier  * Note that the calling thread is about to unlock b.
398*5e96a66cSDavid du Colombier  */
399*5e96a66cSDavid du Colombier void
bwatchUnlock(Block * b)400*5e96a66cSDavid du Colombier bwatchUnlock(Block *b)
401*5e96a66cSDavid du Colombier {
402*5e96a66cSDavid du Colombier 	int i;
403*5e96a66cSDavid du Colombier 	WThread *w;
404*5e96a66cSDavid du Colombier 
405*5e96a66cSDavid du Colombier 	if(bwatchDisabled)
406*5e96a66cSDavid du Colombier 		return;
407*5e96a66cSDavid du Colombier 
408*5e96a66cSDavid du Colombier 	if(b->part != PartData)
409*5e96a66cSDavid du Colombier 		return;
410*5e96a66cSDavid du Colombier 
411*5e96a66cSDavid du Colombier 	w = getWThread();
412*5e96a66cSDavid du Colombier 	for(i=0; i<w->nb; i++)
413*5e96a66cSDavid du Colombier 		if(w->b[i] == b)
414*5e96a66cSDavid du Colombier 			break;
415*5e96a66cSDavid du Colombier 	if(i>=w->nb){
416*5e96a66cSDavid du Colombier 		fprint(2, "%d: unlock of unlocked block %V\n", w->pid, b->score);
417*5e96a66cSDavid du Colombier 		stop();
418*5e96a66cSDavid du Colombier 	}else
419*5e96a66cSDavid du Colombier 		w->b[i] = w->b[--w->nb];
420*5e96a66cSDavid du Colombier }
421*5e96a66cSDavid du Colombier 
422