xref: /plan9/sys/src/cmd/fossil/fossil-acid (revision 588b1baa64338d634bd996f0711914a959505073)
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