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