// pick up the common data structures
rc("cd /sys/src/cmd/fossil; mk 9fsys.acid");
include("/sys/src/cmd/fossil/9fsys.acid");
rc("cd /sys/src/cmd/fossil; mk cache.acid");
include("/sys/src/cmd/fossil/cache.acid");
rc("cd /sys/src/cmd/fossil; mk disk.acid");
include("/sys/src/cmd/fossil/disk.acid");
rc("cd /sys/src/cmd/fossil; mk fs.acid");
include("/sys/src/cmd/fossil/fs.acid");
rc("cd /sys/src/libventi; mk plan9-thread.acid");
include("/sys/src/libventi/plan9-thread.acid");
// make a list of pids from a list of Thread structures
defn _threadlist(t)
{
local l;
l = {};
while t do {
t = (Thread)t;
l = append l, t.pid;
t = t.next;
}
return l;
}
// print info about a VtRendez
defn vtrendez(r)
{
local l, t, w, q;
r = (VtRendez)r;
w = _threadlist(r.wfirst);
if match(pid, w) >= 0 then
print("\twaiting for wakeup\n");
l = (VtLock)r.lk;
q = _threadlist(l.qfirst);
if match(pid, q) >= 0 then
print("\tawakened; waiting for lock\n");
print("\tr=(VtRendez)", r\X, "\n");
print("\tl=(VtLock)", l\X, "\n");
if l.writer != 0 then {
t = (Thread)l.writer;
print("\tvtLock is held by ", t.pid\D, "\n");
}
}
// print info about a VtLock
defn vtlock(l)
{
local t;
l = (VtLock)l;
print("\tl=(VtLock)", l\X, "\n");
if l.writer then {
t = (Thread)l.writer;
print("\tvtLock is held by ", t.pid\D, "\n");
} else if l.readers then
print("\tvtLock is held by ", l.readers\D, " readers\n");
else
print("\tvtLock is not held!\n");
}
// try to say something intelligent about why a process is stuck.
_pauses = {
"open",
"pread",
"pwrite",
"sleep",
"vtSleep",
"vtLock",
};
defn deadlocklist(l)
{
while l do {
setproc(head l);
deadlock();
l = tail l;
}
}
defn deadlock()
{
local stk, frame, name, stallframe, fossilframe, stallname;
stk = strace(*PC, *SP, linkreg(0));
print("setproc(", pid, ") // ", readfile("/proc/"+itoa(pid)+"/args"), "\n");
stallframe = 0;
stallname = "";
fossilframe = 0;
while stk do {
frame = head stk;
name = fmt(frame[0], 'a');
if !stallframe && match(name, _pauses) >= 0 then {
stallframe = frame;
stallname = name;
print("\t", fmt(frame[0], 'a'), "(");
params(frame[2]);
print(") ", pcfile(frame[0]), ":", pcline(frame[0]));
print("\n\t\tcalled from ", fmt(frame[1], 'a'), " ");
pfl(frame[1]);
}
if !fossilframe && regexp("^/sys/src/cmd/fossil/.*", pcfile(frame[0])) then {
fossilframe = frame;
print("\t", fmt(frame[0], 'a'), "(");
params(frame[2]);
print(") ", pcfile(frame[0]), ":", pcline(frame[0]));
print("\n\t\tcalled from ", fmt(frame[1], 'a'), " ");
pfl(frame[1]);
if name == cacheLocalLookup && stallname == vtLock then
print("\twaiting to lock block b=(Block)", *cacheLocalLookup:b\X, "\n");
if name == cacheLocal && stallname == vtSleep then
print("\tsleeping on block b=(Block)", *cacheLocal:b\X, "\n");
if name == blockFlush && stallname == vtSleep then
print("\tsleeping on block b=(Block)", *blockFlush:b\X, "\n");
}
stk = tail stk;
}
if stallname == vtSleep then
vtrendez(*vtSleep:q);
if stallname == vtLock then
vtlock(*vtLock:p);
if !stallframe || !fossilframe then
print("\tconfused\n");
print("\n");
}
// fetch fsys
defn
fsysGet(name)
{
return fsysmain;
}
// dump information about the cache
defn
cacheDump(c)
{
local i, b, x;
c = (Cache)c;
x = c.blocks;
i=0;
loop 1,c.nblocks do {
b = (Block)(x+i);
print(b\X, " ", b.pc\X, " ", b.ref\D, "\n");
i = i+sizeofBlock;
}
}
// print block info
defn
printblist(bl)
{
bl = (BList)bl;
while bl != 0 do {
print("[", bl.part\D, " ", bl.addr\X, " ", bl.vers\D, "]");
bl = bl.next;
if bl != 0 then
print(", ");
}
}
defn
block(b)
{
local i;
b = (Block)b;
print("b=(Block)", b\X, "\n");
print("\tref ", b.ref\D, " nlock ", b.nlock\D, "\n");
print("\tpav=[", b.part\D, " ", b.addr\X, " ", b.vers\D, "]\n");
print("\tprior=");
printblist(b.prior);
print("\n");
print("\tunlink=");
printblist(b.uhead);
print("\n");
}
|