code: plan9front

ref: 403149d7de4dbe4cc4b1fd9cb3a164e51dbccc15
dir: /sys/lib/acid/thread/

View raw version
include("/sys/src/libthread/sched." + objtype + ".acid");

defn labpc(l)
{
	if objtype == "386" || objtype == "amd64" then
		return longjmp;
	return *(l+4);
}

defn labsp(l)
{
	return *l;
}

defn labstk(l)
{
	_stk(labpc(l), labsp(l), 0, 1);
}

defn lablstk(l)
{
	_stk(labpc(l), labsp(l), 0, 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 = {
	"^/sys/src/libc",
	"^/sys/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;
	}
	if a == {} then
		return "{}";
	return itoa(a\X, "%x");
}

stkignorelist = {};

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

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

	if T.state == Running then{
		pc = *PC;
		stk = strace(*PC, *SP, linkreg(0));
	}else{
		pc = labpc(T.sched);
		stk = strace(labpc(T.sched), labsp(T.sched), 0);
	}
	firstpc = pc;
	lastpc0 = 0;
	pc0 = 0;
	stop = 0;
	ostk = stk;
	while stk && !stop do {
		file = pcfile(pc);
		if !regexp("^/sys/src/libc/", file)
		&& !regexp("^/sys/src/libthread/", file) 
		&& match(file, stkignore)==-1 then
			stop = 1;
		else if stk[0][1] == 0xfefefefe then {
			pc = ostk[0][1];
			pc0 = ostk[1][0];
			stop = 1;
		}else{
			lastpc0 = pc0;
			frame = head stk;
			stk = tail stk;
			nextframe = head stk;
			pc = frame[1];
			pc0 = nextframe[0];
		}
	}
	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 = T.nextt;
	}
	setproc(mainpid);
}

defn threads(){
	local P;

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

defn stacks(){
	local P, mainpid;

	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 = P.next;
		print("\n");
	}
	setproc(mainpid);
}

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

	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, " / ", T.stksize\D, "\n");
			T = T.nextt;
		}
		P = P.next;
	}
	setproc(mainpid);
}

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

defn threadstks(P){
	complex Proc P;
	local T, Tq, mainpid, pref, ign;

	mainpid = pid;
	pref = stkprefix;
	stkprefix = pref+"\t\t";
	ign = stkignore;
	stkignore = {
		"^/sys/src/libthread/",
		"^/sys/src/libc/(386|arm|sparc|power|mips)/"
	};
	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 = 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;

	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{
		lstk();
	} 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;
	}
}

print("/sys/lib/acid/thread");