1// pick up the common data structures 2 3rc("cd /sys/src/cmd/fossil; mk 9fsys.acid"); 4include("/sys/src/cmd/fossil/9fsys.acid"); 5rc("cd /sys/src/cmd/fossil; mk cache.acid"); 6include("/sys/src/cmd/fossil/cache.acid"); 7rc("cd /sys/src/cmd/fossil; mk disk.acid"); 8include("/sys/src/cmd/fossil/disk.acid"); 9rc("cd /sys/src/cmd/fossil; mk fs.acid"); 10include("/sys/src/cmd/fossil/fs.acid"); 11rc("cd /sys/src/liboventi; mk plan9-thread.acid"); 12include("/sys/src/liboventi/plan9-thread.acid"); 13 14// make a list of pids from a list of Thread structures 15defn _threadlist(t) 16{ 17 local l; 18 19 l = {}; 20 while t do { 21 t = (Thread)t; 22 l = append l, t.pid; 23 t = t.next; 24 } 25 return l; 26} 27 28// print info about a VtRendez 29defn vtrendez(r) 30{ 31 local l, t, w, q; 32 33 r = (VtRendez)r; 34 w = _threadlist(r.wfirst); 35 if match(pid, w) >= 0 then 36 print("\twaiting for wakeup\n"); 37 38 l = (VtLock)r.lk; 39 q = _threadlist(l.qfirst); 40 if match(pid, q) >= 0 then 41 print("\tawakened; waiting for lock\n"); 42 43 print("\tr=(VtRendez)", r\X, "\n"); 44 print("\tl=(VtLock)", l\X, "\n"); 45 if l.writer != 0 then { 46 t = (Thread)l.writer; 47 print("\tvtLock is held by ", t.pid\D, "\n"); 48 } 49} 50 51// print info about a VtLock 52defn vtlock(l) 53{ 54 local t; 55 56 l = (VtLock)l; 57 print("\tl=(VtLock)", l\X, "\n"); 58 if l.writer then { 59 t = (Thread)l.writer; 60 print("\tvtLock is held by ", t.pid\D, "\n"); 61 } else if l.readers then 62 print("\tvtLock is held by ", l.readers\D, " readers\n"); 63 else 64 print("\tvtLock is not held!\n"); 65} 66 67// try to say something intelligent about why a process is stuck. 68_pauses = { 69 open, 70 pread, 71 pwrite, 72 sleep, 73 vtSleep, 74 vtLock, 75 vtRLock, 76}; 77 78defn deadlocklist(l) 79{ 80 while l do { 81 setproc(head l); 82 deadlock(); 83 l = tail l; 84 } 85} 86 87defn deadlock() 88{ 89 local stk, frame, name, stallframe, fossilframe, stallname; 90 91 stk = strace(*PC, *SP, linkreg(0)); 92 93 print("setproc(", pid, ") // ", readfile("/proc/"+itoa(pid)+"/args"), "\n"); 94 stallframe = 0; 95 stallname = ""; 96 fossilframe = 0; 97 frame = {0}; 98 while stk do { 99 lastframe = frame; 100 frame = head stk; 101 name = fmt(frame[0], 'a'); 102 if !stallframe && match(name, _pauses) >= 0 then { 103 stallframe = frame; 104 stallname = name; 105 print("\t", fmt(frame[0], 'a'), "("); 106 params(frame[2]); 107 print(") ", pcfile(frame[0]), ":", pcline(frame[0])); 108 print("\n\t\tcalled from ", fmt(frame[1], 'a'), " "); 109 pfl(frame[1]); 110 } 111 if !fossilframe && regexp("^/sys/src/cmd/fossil/.*", pcfile(frame[0])) then { 112 if !stallframe then { 113 stallframe = lastframe; 114 stallname = fmt(lastframe[0], 'a'); 115 print("\tunexpected stall: ", stallname, "\n"); 116 if match(stallname, _pauses) >= 0 then 117 print("\t\t but it matches!\n"); 118 } 119 fossilframe = frame; 120 print("\t", fmt(frame[0], 'a'), "("); 121 params(frame[2]); 122 print(") ", pcfile(frame[0]), ":", pcline(frame[0])); 123 print("\n\t\tcalled from ", fmt(frame[1], 'a'), " "); 124 pfl(frame[1]); 125 126 if name == cacheLocalLookup && stallname == vtLock then 127 print("\twaiting to lock block b=(Block)", *cacheLocalLookup:b\X, "\n"); 128 if name == cacheLocal && stallname == vtSleep then 129 print("\tsleeping on block b=(Block)", *cacheLocal:b\X, "\n"); 130 if name == blockWrite && stallname == vtSleep then 131 print("\tsleeping on block b=(Block)", *blockFlush:b\X, "\n"); 132 } 133 stk = tail stk; 134 } 135 136 if stallname == vtSleep then 137 vtrendez(*vtSleep:q); 138 if stallname == vtLock then 139 vtlock(*vtLock:p); 140 if !stallframe || !fossilframe then { 141 print("\tconfused:"); 142 if !stallframe then print(" stallframe?"); 143 if !fossilframe then print(" fossilframe?"); 144 print("\n"); 145 } 146 print("\n"); 147} 148 149// fetch fsys 150defn 151fsysGet(name) 152{ 153 return fsysmain; 154} 155 156// dump information about the cache 157defn 158cacheDump(c) 159{ 160 local i, b, x; 161 162 c = (Cache)c; 163 x = c.blocks; 164 i=0; 165 loop 1,c.nblocks do { 166 b = (Block)(x+i); 167 print(b\X, " ", b.pc\X, " ", b.ref\D, "\n"); 168 i = i+sizeofBlock; 169 } 170} 171 172// print block info 173defn 174printblist(bl) 175{ 176 bl = (BList)bl; 177 while bl != 0 do { 178 print("[", bl.part\D, " ", bl.addr\X, " ", bl.vers\D, "]"); 179 bl = bl.next; 180 if bl != 0 then 181 print(", "); 182 } 183} 184 185defn 186block(b) 187{ 188 local i; 189 190 b = (Block)b; 191 print("b=(Block)", b\X, "\n"); 192 print("\tref ", b.ref\D, " nlock ", b.nlock\D, "\n"); 193 print("\tpav=[", b.part\D, " ", b.addr\X, " ", b.vers\D, "]\n"); 194 print("\tprior="); 195 printblist(b.prior); 196 print("\n"); 197 print("\tunlink="); 198 printblist(b.uhead); 199 print("\n"); 200} 201