xref: /plan9/sys/lib/acid/thread (revision 3c2ddefeebfd7a80eaebf272955335c2cf163bd5)
1include("/sys/src/libthread/sched.acid");
2
3defn labpc(l)
4{
5	if objtype == "386" then
6		return longjmp;
7	return *(l+4);
8}
9
10defn labsp(l)
11{
12	return *l;
13}
14
15defn labstk(l)
16{
17	_stk(labpc(l), labsp(l), 0, 0);
18}
19
20defn lablstk(l)
21{
22	_stk(labpc(l), labsp(l), 0, 1);
23}
24
25defn altfmt(A){
26	local i, s, yes;
27	complex Alt A;
28
29	s = "alt(";
30	s = s + "tag(*" + itoa(A.tag, "%x") + "=" + itoa(*A.tag, "%x") + ") ";
31	i = 0;
32	yes = 0;
33	while A.op != CHANEND && A.op != CHANNOBLK do{
34		if A.op != CHANNOP then{
35			if yes then s = s + " ";
36			s = s + itoa(i, "%d");
37			s = s + ":";
38			if A.op == CHANSND then s = s + "send";
39			if A.op == CHANRCV then s = s + "recv";
40			s = s + "(channel(";
41			s = s + itoa(A.c, "%x");
42			s = s + "))";
43			yes = 1;
44		}
45		i = i + 1;
46		A = (Alt)(A + sizeofAlt);
47	}
48	if A.op==CHANNOBLK then{
49		if yes then s = s + " ";
50		s = s + "noblock";
51	}
52	s = s + ")";
53	return s;
54}
55
56defn alt(A){
57	print(altfmt(A), "\n");
58}
59
60threadignsrc = {
61	"^/sys/src/libc",
62	"^/sys/src/libthread",
63};
64
65defn fnname(a){
66	local sym, s;
67
68	s = symbols;
69	while s do {
70		sym = head s;
71		if sym[2] == a then
72			return sym[0];
73		s = tail s;
74	}
75	if a == {} then
76		return "{}";
77	return itoa(a\X, "%x");
78}
79
80stkignorelist = {};
81
82defn stkignore(s){
83	append stkignorelist, s;
84}
85
86defn threadstkline(T){
87	local ostk, stk, frame, pc, pc0, file, lastpc0, s, sym, i, stop;
88
89	if T.state == Running then{
90		pc = *PC;
91		stk = strace(*PC, *SP, linkreg(0));
92	}else{
93		pc = labpc(T.sched);
94		stk = strace(labpc(T.sched), labsp(T.sched), 0);
95	}
96	firstpc = pc;
97	lastpc0 = 0;
98	pc0 = 0;
99	stop = 0;
100	ostk = stk;
101	while stk && !stop do {
102		file = pcfile(pc);
103		if !regexp("^/sys/src/libc/", file)
104		&& !regexp("^/sys/src/libthread/", file)
105		&& match(file, stkignore)==-1 then
106			stop = 1;
107		else if stk[0][1] == 0xfefefefe then {
108			pc = ostk[0][1];
109			pc0 = ostk[1][0];
110			stop = 1;
111		}else{
112			lastpc0 = pc0;
113			frame = head stk;
114			stk = tail stk;
115			nextframe = head stk;
116			pc = frame[1];
117			pc0 = nextframe[0];
118		}
119	}
120	file = pcfile(pc);
121	s = file+":"+itoa(pcline(pc), "%d");
122	if pc0 != 0 then
123		s = s + " "+fnname(pc0);
124	return s;
125}
126
127defn threadfmt(T){
128	complex Thread T;
129	local A, yes, i, P, s;
130
131	P = (Proc)T.proc;
132	s = "t=(Thread)"+itoa(T, "%-10x")+" ";
133
134	if T.state == Running then
135		s = s + "Running    ";
136	else if T.state == Ready then
137		s = s + "Ready      ";
138	else if T.state == Rendezvous then
139		s = s + "Rendez     ";
140	else
141		s = s + "Bad state "+itoa(T.state, "%x")+" ";
142
143	A = (Alt)T.alt;
144	if 1 then
145		s = s + threadstkline(T);
146	else if T.chan == Chanalt then
147		s = s + altfmt(T.alt);
148	else if T.chan == Chansend then
149		s = s + "send(Channel("+itoa(A.c, "%x")+"))";
150	else if T.chan == Chanrecv then
151		s = s + "recv(Channel("+itoa(A.c, "%x")+"))";
152	else
153		s = s + threadstkline(T);
154
155	if T.moribund == 1 then
156		s = s + " Moribund";
157	if T.cmdname != 0 then
158		s = s + " ["+*(T.cmdname\s)+"]";
159	return s;
160}
161
162defn thread(T){
163	print(threadfmt(T), "\n");
164}
165
166defn pthreads(P){
167	complex Proc P;
168	local T, Tq, mainpid;
169
170	mainpid = pid;
171	setproc(P.pid);
172	Tq = (Tqueue)P.threads;
173	T = (Thread)Tq.$head;
174	while T != 0 do{
175		print("\t");
176		thread(T);
177		T = T.nextt;
178	}
179	setproc(mainpid);
180}
181
182defn threads(){
183	local P;
184
185	P = (Proc)_threadpq.$head;
186	while P != 0 do{
187		if P != (Proc)_threadpq.$head then print("\n");
188		lproc(P);
189		P = P.next;
190	}
191}
192
193defn stacks(){
194	local P, mainpid;
195
196	mainpid = pid;
197	P = (Proc)_threadpq.$head;
198	while P != 0 do{
199		proc(P);
200	//	setproc(P.pid);
201	//	if P.thread==0 then{
202	//		print("=== thread scheduler stack\n");
203	//		stk();
204	//	}
205	//	print("threadstks(", P\X, ")\n");
206		threadstks(P);
207		P = P.next;
208		print("\n");
209	}
210	setproc(mainpid);
211}
212
213defn stacksizes(){
214	local P, T, Tq, top, sp, mainpid;
215
216	mainpid = pid;
217	P = (Proc)_threadpq.$head;
218	while P != 0 do{
219		P = (Proc)P;
220		Tq = (Tqueue)P.threads;
221		T = (Thread)Tq.$head;
222		while T != 0 do{
223			top = T.stk+T.stksize;
224			if T.state==Running then {
225				sp = *SP;
226			}else{
227				sp = *(T.sched);
228			}
229			sp = *(T.sched);
230			print(top-sp\D, " / ", T.stksize\D, "\n");
231			T = T.nextt;
232		}
233		P = P.next;
234	}
235	setproc(mainpid);
236}
237
238defn lproc(P){
239	proc(P);
240	pthreads(P);
241}
242
243defn threadstks(P){
244	complex Proc P;
245	local T, Tq, mainpid, pref, ign;
246
247	mainpid = pid;
248	pref = stkprefix;
249	stkprefix = pref+"\t\t";
250	ign = stkignore;
251	stkignore = {
252		"^/sys/src/libthread/",
253		"^/sys/src/libc/(386|arm|alpha|sparc|power|mips)/"
254	};
255	setproc(P.pid);
256	Tq = (Tqueue)P.threads;
257	T = (Thread)Tq.$head;
258	while T != 0 do{
259	//	print("=============================\n");
260	//	print("  thread(", T\X, ")\n");
261		print("\t");
262		thread(T);
263		threadstk(T);
264		T = T.nextt;
265		print("\n");
266	}
267	setproc(mainpid);
268	stkprefix = pref;
269	stkignore = ign;
270}
271
272defn proc(P){
273	complex Proc P;
274
275	print("p=(Proc)", itoa(P, "%-10x"), " pid ", P.pid\D, " ");
276	if P.thread==0 then
277		print(" Sched");
278	else
279		print(" Running");
280	print("\n");
281}
282
283defn procs(){
284	local P;
285
286	P = (Proc)_threadpq.$head;
287	while P != 0 do{
288		proc(P);
289		P = P.next;
290	}
291}
292
293defn threadlstk(T){
294	complex Thread T;
295	local P, mainpid;
296
297	P = (Proc)T.proc;
298	mainpid = pid;
299	setproc(P.pid);
300
301	if T.state == Running then{
302		lstk();
303	} else {
304		lablstk(T.sched);
305	}
306	setproc(mainpid);
307}
308
309defn threadstk(T){
310	complex Thread T;
311	local P, mainpid;
312
313	P = (Proc)T.proc;
314	mainpid = pid;
315	setproc(P.pid);
316
317	if T.state == Running then{
318		stk();
319	} else {
320		labstk(T.sched);
321	}
322	setproc(mainpid);
323}
324
325defn tqueue(Q) {
326	complex Tqueue Q;
327
328	while Q != 0 do {
329		print(Q.$head\X, " ");
330		Q = *(Q.$tail);
331
332	}
333	print("#\n");
334}
335
336defn channel(C) {
337	complex Channel C;
338	local i, p;
339
340	print("channel ", C\X);
341	if C.freed then {
342		print(" (moribund)");
343	}
344	print("\n");
345	print("\telementsize=", C.e\D, " buffersize=", C.s, "\n");
346	if C.s then {
347		print("\t", C.n\D, " values in channel:\n");
348		print("\t");
349		p = C.v+C.e*(C.f%C.s);
350		loop 1,C.n do {
351			if C.e==4 then {
352				print((*p)\X, " ");
353			}else {
354				print("data(", (*p)\X, ") ");
355			}
356			p = p+C.e;
357			if p == C.v+C.s*C.e then {
358				p = C.v;
359			}
360		}
361	}
362	print("\n");
363	print(C.nentry\D, " queue slots:\n");
364	i=0;
365	loop 1,C.nentry do {
366		if C.qentry[i] then
367			print("\t", altfmt(C.qentry[i]), "\n");
368		else
369			print("\t<empty>\n");
370		i=i+1;
371	}
372}
373
374print("/sys/lib/acid/thread");
375