
defn labpc(l)
{
	complex Label l;

	return l.pc;
}

defn label(l)
{
	complex Label l;

	if objtype == "386" then
		return {"PC", l.pc, "BX", l.bx, "SP", l.sp, "BP", l.bp, "SI", l.si, "DI", l.di};
	return {};
}


defn labstk(l)
{
	_stk(label(l), 0);
}

defn lablstk(l)
{
	_stk(label(l), 1);
}

defn altfmt(A){
	local i, s, yes;
	complex Alt A;

	s = "alt(";
	s = s + "tag(*" + itoa(A.tag, "%x") + "=" + itoa(*A.tag, "%x") + ") ";
	i = 0;
	yes = 0;
	while A.op != CHANEND && A.op != CHANNOBLK do{
		if A.op != CHANNOP then{
			if yes then s = s + " ";
			s = s + itoa(i, "%d");
			s = s + ":";
			if A.op == CHANSND then s = s + "send";
			if A.op == CHANRCV then s = s + "recv";
			s = s + "(channel(";
			s = s + itoa(A.c, "%x");
			s = s + "))";
			yes = 1;
		}
		i = i + 1;
		A = (Alt)(A + sizeofAlt);
	}
	if A.op==CHANNOBLK then{
		if yes then s = s + " ";
		s = s + "noblock";
	}
	s = s + ")";
	return s;
}

defn alt(A){
	print(altfmt(A), "\n");
}

threadignsrc = {
	"plan9/src/libc",
	"plan9/src/libthread",
};

defn fnname(a){
	local sym, s;

	s = symbols;
	while s do {
		sym = head s;
		if sym[2] == a then
			return sym[0];
		s = tail s;
	}
	return itoa(a, "%x");
}

stkignorelist = {};

defn stkignore(s){
	append stkignorelist, s;
}

defn threadstkline(T){
	local stk, frame, pc, pc0, file, s, sym, i, stop;

	if T.state == Running then
		stk = strace({});
	else
		stk = strace(label(T.sched));

	stop = 0;
	while stk && !stop do {
		frame = head stk;
		stk = tail stk;
		pc = frame[2];
		pc0 = frame[0];
		file = pcfile(pc);
		if !regexp("plan9/src/libc/", file)
		&& !regexp("plan9/src/libthread/", file) 
		&& match(file, stkignore)==-1 then
			stop = 1;
	}
	file = pcfile(pc);
	s = file+":"+itoa(pcline(pc), "%d");
	if pc0 != 0 then 
		s = s + " "+fnname(pc0);
	return s;
}

defn threadfmt(T){
	complex Thread T;
	local A, yes, i, P, s;

	P = (Proc)T.proc;
	s = "t=(Thread)"+itoa(T, "%-10x")+" ";

	if T.state == Running then
		s = s + "Running    ";
	else if T.state == Ready then
		s = s + "Ready      ";
	else if T.state == Rendezvous then
		s = s + "Rendez     ";
	else
		s = s + "Bad state "+itoa(T.state, "%x")+" ";

	A = (Alt)T.alt;
	if 1 then
		s = s + threadstkline(T);
	else if T.chan == Chanalt then
		s = s + altfmt(T.alt);
	else if T.chan == Chansend then
		s = s + "send(Channel("+itoa(A.c, "%x")+"))";
	else if T.chan == Chanrecv then
		s = s + "recv(Channel("+itoa(A.c, "%x")+"))";
	else
		s = s + threadstkline(T);

	if T.moribund == 1 then
		s = s + " Moribund";
	if T.cmdname != 0 then
		s = s + " ["+*(T.cmdname\s)+"]";
	return s;
}

defn thread(T){
	print(threadfmt(T), "\n");
}

defn pthreads(P){
	complex Proc P;
	local T, Tq, mainpid;

	mainpid = pid;
	setproc(P.pid);
	Tq = (Tqueue)P.threads;
	T = (Thread)Tq.$head;
	while T != 0 do{
		print("\t");
		thread(T);
		T = (Thread)T.nextt;
	}
	setproc(mainpid);
}

defn threads(){
	local P;
	complex Pqueue _threadpq;

	P = (Proc)_threadpq.$head;
	while P != 0 do{
		if P != (Proc)_threadpq.$head then print("\n");
		lproc(P);
		P = (Proc)P.next;
	}
}

defn stacks(){
	local P, mainpid;
	complex Pqueue _threadpq;

	stkprefix = "";
	mainpid = pid;
	P = (Proc)_threadpq.$head;
	while P != 0 do{
		proc(P);
	//	setproc(P.pid);
	//	if P.thread==0 then{
	//		print("=== thread scheduler stack\n");
	//		stk();
	//	}
	//	print("threadstks(", P\X, ")\n");
		threadstks(P);
		P = (Proc)P.next;
		print("\n");
	}
	setproc(mainpid);
}

defn stacksizes(){
	local P, T, Tq, top, sp, mainpid;
	complex Pqueue _threadpq;

	mainpid = pid;
	P = (Proc)_threadpq.$head;
	while P != 0 do{
		P = (Proc)P;
		Tq = (Tqueue)P.threads;
		T = (Thread)Tq.$head;
		while T != 0 do{
			top = T.stk+T.stksize;
			if T.state==Running then {
				sp = *SP;
			}else{
				sp = *(T.sched);
			}
			sp = *(T.sched);
			print(top-sp\D, "\n");
			T = (Thread)T.nextt;
		}
		P = P.next;
	}
	setproc(mainpid);
}

defn lproc(P){
	proc(P);
	pthreads(P);
}

threadstkignore = {
	"plan9/src/libthread/",
	"plan9/src/libc/(386|arm|alpha|sparc|power|mips)/"
};
defn threadstks(P){
	complex Proc P;
	local T, Tq, mainpid, pref, ign;

	mainpid = pid;
	pref = stkprefix;
	stkprefix = pref+"\t\t";
	ign = stkignore;
	stkignore = threadstkignore;
	setproc(P.pid);
	Tq = (Tqueue)P.threads;
	T = (Thread)Tq.$head;
	while T != 0 do{
	//	print("=============================\n");
	//	print("  thread(", T\X, ")\n");
		print("\t");
		thread(T);
		threadstk(T);
		T = (Thread)T.nextt;
		print("\n");
	}
	setproc(mainpid);
	stkprefix = pref;
	stkignore = ign;
}

defn proc(P){
	complex Proc P;

	print("p=(Proc)", itoa(P, "%-10x"), " pid ", P.pid\D, " ");
	if P.thread==0 then
		print(" Sched");
	else
		print(" Running");
	print("\n");
}

defn procs(){
	local P;
	complex Pqueue _threadpq;

	P = (Proc)_threadpq.$head;
	while P != 0 do{
		proc(P);
		P = P.next;
	}
}

defn threadlstk(T){
	complex Thread T;
	local P, mainpid;

	P = (Proc)T.proc;
	mainpid = pid;
	setproc(P.pid);

	if T.state == Running then{
		lstk();
	} else {
		lablstk(T.sched);
	}
	setproc(mainpid);
}

defn threadstk(T){
	complex Thread T;
	local P, mainpid;

	P = (Proc)T.proc;
	mainpid = pid;
	setproc(P.pid);

	if T.state == Running then{
		stk();
	} else {
		labstk(T.sched);
	}
	setproc(mainpid);
}

defn tqueue(Q) {
	complex Tqueue Q;

	while Q != 0 do {
		print(Q.$head\X, " ");
		Q = *(Q.$tail);
	
	}
	print("#\n");
}

defn channel(C) {
	complex Channel C;
	local i, p;

	print("channel ", C\X);
	if C.freed then {
		print(" (moribund)");
	}
	print("\n");
	print("\telementsize=", C.e\D, " buffersize=", C.s, "\n");
	if C.s then {
		print("\t", C.n\D, " values in channel:\n");
		print("\t");
		p = C.v+C.e*(C.f%C.s);
		loop 1,C.n do {
			if C.e==4 then {
				print((*p)\X, " ");
			}else {
				print("data(", (*p)\X, ") ");
			}
			p = p+C.e;
			if p == C.v+C.s*C.e then {
				p = C.v;
			}
		}
	}
	print("\n");
	print(C.nentry\D, " queue slots:\n");
	i=0;
	loop 1,C.nentry do {
		if C.qentry[i] then
			print("\t", altfmt(C.qentry[i]), "\n");
		else
			print("\t<empty>\n");
		i=i+1;
	}
}

defn polling() {
	local i, c, t, p, pf;

	p=(Poll)polls; pf=(struct_pollfd)pfd; loop 1,*npoll do {
		print("\tfd ", pf.fd\D, "   ");
		if pf.events & 1 then
			print("r");
		else if pf.events & 2 then
 			print("w");
		else
			print(pf.events\D);
		print(" chan Channel(", p.c\X, ")\n");
		p = (Poll)(p+sizeofPoll);
		pf = (struct_pollfd)(pf+sizeofstruct_pollfd);
	}

	c=sleepchan; t=sleeptime; loop 1,*nsleep do {
		print("\tsleep ", *t\D, " Channel(", *c\X, ")\n");
		c++;
		t++;
	}
}

print(acidfile);
